diff --git a/resources/assets.py b/resources/assets.py index f628453c..7e9e6b5b 100644 --- a/resources/assets.py +++ b/resources/assets.py @@ -104,6 +104,9 @@ def generate(rm: ResourceManager): tex = 'firmalife:block/%s_%s' % (trd, variant) rm.block_model('firmalife:%s_%s' % (trd, variant), {'west': tex, 'east': tex, 'north': tex, 'south': tex, 'particle': tex, 'up': 'firmalife:block/%s_top' % trd, 'down': 'firmalife:block/%s_top' % trd}) + rm.blockstate('stovetop_grill').with_lang(lang('stovetop grill')).with_tag('minecraft:mineable/pickaxe').with_block_loot('tfc:wrought_iron_grill') + rm.blockstate('stovetop_pot').with_lang(lang('stovetop pot')).with_tag('minecraft:mineable/pickaxe').with_block_loot('tfc:ceramic/pot') + rm.block_model('dribbler', parent='firmalife:block/sprinkler', textures={'0': 'firmalife:block/metal/full/stainless_steel'}) rm.blockstate('sprinkler', model='firmalife:block/sprinkler').with_lang(lang('sprinkler')).with_tag('minecraft:mineable/pickaxe').with_block_loot('firmalife:sprinkler') rm.item_model('sprinkler', parent='firmalife:block/sprinkler', no_textures=True) diff --git a/resources/constants.py b/resources/constants.py index 99b8e7fa..6f271cbf 100644 --- a/resources/constants.py +++ b/resources/constants.py @@ -22,7 +22,7 @@ class Wood(NamedTuple): 'treated_wood': 'minecraft:mineable/axe' } COLORS = ('white', 'orange', 'magenta', 'light_blue', 'yellow', 'lime', 'pink', 'gray', 'light_gray', 'cyan', 'purple', 'blue', 'brown', 'green', 'red', 'black') -BLOCK_ENTITIES = ('oven_bottom', 'oven_top', 'drying_mat', 'beehive', 'solar_drier', 'mixing_bowl', 'iron_composter', 'string', 'berry_bush', 'large_planter', 'bonsai_planter', 'trellis_planter', 'hanging_planter', 'quad_planter', 'climate_station', 'hydroponic_planter', 'vat', 'oven_hopper', 'ashtray') +BLOCK_ENTITIES = ('oven_bottom', 'oven_top', 'drying_mat', 'beehive', 'solar_drier', 'mixing_bowl', 'iron_composter', 'string', 'berry_bush', 'large_planter', 'bonsai_planter', 'trellis_planter', 'hanging_planter', 'quad_planter', 'climate_station', 'hydroponic_planter', 'vat', 'oven_hopper', 'ashtray', 'stovetop_grill', 'stovetop_pot') EXTRA_FLUIDS = ('yeast_starter', 'coconut_milk', 'yak_milk', 'goat_milk', 'curdled_yak_milk', 'curdled_goat_milk', 'pina_colada', 'cream', 'chocolate') JARS: Sequence[Tuple[str, int, str, str]] = ( ('honey', 1, 'minecraft:block/honey_block_side', 'firmalife:raw_honey'), diff --git a/resources/data.py b/resources/data.py index 2f94a7ed..97c2c1ed 100644 --- a/resources/data.py +++ b/resources/data.py @@ -64,6 +64,7 @@ def generate(rm: ResourceManager): rm.item_tag('tfc:compost_greens_low', 'firmalife:fruit_leaf') rm.item_tag('foods/cooked_meats_and_substitutes', '#tfc:foods/cooked_meats', 'firmalife:food/tofu') rm.item_tag('forge:leather', 'firmalife:pineapple_leather') + rm.item_tag('usable_in_stovetop_soup', '#tfc:foods/usable_in_soup') block_and_item_tag(rm, 'tfc:wild_fruits', 'firmalife:plant/pineapple_bush', 'firmalife:plant/nightshade_bush', 'firmalife:plant/fig_sapling', 'firmalife:plant/cocoa_sapling') diff --git a/resources/generate_book.py b/resources/generate_book.py index 89c66b27..24bc561a 100644 --- a/resources/generate_book.py +++ b/resources/generate_book.py @@ -48,6 +48,12 @@ def make_book(rm: ResourceManager, i18n: I18n, local_instance: bool = False): book.template('drying_recipe', custom_component(0, 0, 'DryingComponent', {'recipe': '#recipe'}), text_component(0, 45)) book.category('firmalife', 'Firmalife', 'All about the Firmalife addon', 'firmalife:cured_oven_top', is_sorted=True, entries=( + entry('differences_from_tfc', 'Differences from TFC (Read first!)', 'tfc:food/wheat_bread', pages=( + text('Firmalife makes a few changes to how things operate in regular TFC. This chapter exists to help direct you towards areas where this is very different.'), + text('$(l:firmalife:firmalife/cheese)Cheese$() is made through a more complex process. It can be placed in world, and has the option of aging in a $(l:firmalife:firmalife/cellar)Cellar$().', title='Cheese Aging'), + text('$(l:firmalife:firmalife/bread)Bread$() is made through a more complex process, requiring yeast and sweetener. Regular TFC bread makes flatbread, which is worse nutritionally.', title='Cheese Aging'), + text('Firmalife has a greater emphasis on sugar. While it can still be obtained through sugar cane, consider using honey (from bees) or making sugar from beets!', title='Sweeteners'), + )), entry('cheese', 'Cheese', 'firmalife:food/gouda', pages=( text('Making $(thing)cheese$() in Firmalife is a little more involved than in vanilla TFC. There are two new kinds of milk: $(thing)Yak Milk$(), and $(thing)Goat Milk$(). These are obtained from milking the $(l:mechanics/animal_husbandry#yak)Yak$() and $(l:mechanics/animal_husbandry#goat)Goat$(), respectively. Milking the $(l:mechanics/animal_husbandry#cow)Cow$() still produces the old kind of milk.'), text('Like usual, milk must be $(thing)curdled$() first. To curdle milk, you need $(thing)Rennet$(). Rennet comes from the stomach of $(thing)Ruminant$() animals. This includes $(l:mechanics/animal_husbandry#yak)Yaks$(), $(l:mechanics/animal_husbandry#cow)Cows$(), $(l:mechanics/animal_husbandry#sheep)Sheep$(), $(l:mechanics/animal_husbandry#goat)Goats$(), and $(l:mechanics/animal_husbandry#musk_ox)Musk Oxen$(). To curdle milk, seal it in a $(l:mechanics/barrels)Barrel$() with Rennet for 4 hours.'), @@ -167,7 +173,7 @@ def make_book(rm: ResourceManager, i18n: I18n, local_instance: bool = False): empty_last_page() )), entry('ovens', 'Ovens', 'firmalife:cured_oven_top', pages=( - text('$(thing)Ovens$() are a great way of cooking lots of food in a way that improves their shelf life. Oven-baked food decays at 90% of the rate of regular food. Ovens are a multiblock structure consisting of a $(thing)Bottom Oven$(), $(thing)Top Oven$(), and optionally $(thing)Chimneys$(). These blocks start off as clay, and must be $(thing)Cured$() by raising their temperature to a certain amount for long enough.'), + text('$(thing)Ovens$() are a great way of cooking lots of food in a way that improves their shelf life. Oven-baked food decays at 90% of the rate of regular food. Ovens are a multiblock structure consisting of a $(thing)Bottom Oven$(), $(thing)Top Oven$(), and optionally $(thing)Chimneys$(). These blocks start off as clay, and must be $(thing)Cured$() by raising their temperature to a certain amount for long enough.$(br)$(l:firmalife:firmalife/oven_appliances)Oven Appliances$() extend oven functionality.'), clay_knapping('tfc:clay_knapping/oven_top', 'The recipe for the bottom oven.'), clay_knapping('tfc:clay_knapping/oven_bottom', 'The recipe for the top oven.'), clay_knapping('tfc:clay_knapping/oven_chimney', 'The recipe for the oven chimney .'), @@ -189,9 +195,17 @@ def make_book(rm: ResourceManager, i18n: I18n, local_instance: bool = False): text('The Bottom Oven is used to hold fuel, which may only be logs. Press $(item)$(k:key.use)$() to add or remove them. The bottom oven is also the part of the oven which may be lit with a $(thing)Firestarter$() or other tool. It transfers heat contained in it to the top oven.'), text('The Top Oven contains the items that are being cooked. It will draw heat from the Bottom Oven and slowly release it over time. This means that even if your fuel runs out, your Top Oven can continue to work for a little while. Adding items to it is as simple as pressing $(item)$(k:key.use)$(). Remember to use a $(thing)Peel$() to remove the items after.'), text('Curing Oven blocks is easy, but requires patience. Simply start running your Bottom Oven as you would normally, and then wait. If an oven block is above 600 degrees for about 80 seconds, it will cure itself and any oven blocks around it. The curing effect will pass all the way up chimneys nearby.'), + empty_last_page() + )), + entry('oven_appliances', 'Oven Appliances', 'tfc:vat', pages=( + text('$(l:firmalife:firmalife/ovens)Ovens$() have a number of devices that interact with them, that extend their functionality. This is because ovens are modular in nature.'), crafting('firmalife:crafting/oven_hopper', text_contents='The $(thing)Oven Hopper$() will input logs into any Bottom Oven that it is facing. It holds 16 logs (4 stacks of 4, like a log pile), and its inventory is fed by dropping items in the top. It can also be fed via automation from other mods.'), crafting('firmalife:crafting/ashtray', text_contents='The $(thing)Ashtray$() collects $(thing)Wood Ash$() when placed below a $(thing)Bottom Oven Block$(). There is a 0.5 chance it gains ash when fuel is consumed. Ash is extracted with $(item)$(k:key.use)$() and inserted via attacking it.'), - empty_last_page() + crafting('firmalife:crafting/vat', text_contents='The $(thing)Vat$() produces some select boiling recipes in bulk. It has one slot for items, and 10,000mB of fluid space, similar to a barrel.'), + text('For example, the vat can be used to make $(thing)Olive Oil Water$() using a ratio of 1 Olive Paste to 200 mB Water. To use a vat, $(item)$(k:key.use)$() it with fluids and items to add them to the inventory. With an empty hand and $(item)$(k:key.sneak)$() held, click to seal and unseal the vat. A vat will not boil until it is sealed.'), + text('Vats should be placed on the block above a $(thing)Bottom Oven$(). If the vat would overflow on completion of the recipe, it will not boil, so be sure not to overfill it -- especially with recipes that produce more fluid than they consume!'), + two_tall_block_spotlight('', '', 'firmalife:cured_oven_bottom', 'firmalife:vat'), + text('Pots and Grills from TFC can be placed on top of a $(thing)Bottom Oven$(). These devices will get heat automatically from the bottom oven. They come with a couple restrictions: Each has only 4 slots, and the pot is only used for making soup. It cannot execute regular pot recipes.'), )), entry('bread', 'Bread', 'tfc:food/rye_bread', pages=( text('To make $(thing)Bread$(), one first must get $(thing)Yeast$(). To get your first yeast, seal $(l:firmalife:firmalife/drying)Dried Fruit$() in a Barrel of $(thing)Water$(). After three days, $(thing)Yeast Starter$() will form.$(br)From now on, your yeast can be fed by sealing Yeast Starter in a Barrel with $(thing)Flour$(). This causes it to multiply. 1 flour per 100mB of Yeast produces 600mB of Yeast. That\'s a good deal!'), diff --git a/src/main/java/com/eerussianguy/firmalife/client/FLClientEvents.java b/src/main/java/com/eerussianguy/firmalife/client/FLClientEvents.java index 03429eed..9cb7a2ab 100644 --- a/src/main/java/com/eerussianguy/firmalife/client/FLClientEvents.java +++ b/src/main/java/com/eerussianguy/firmalife/client/FLClientEvents.java @@ -3,6 +3,8 @@ import java.util.function.Supplier; import java.util.stream.Stream; +import com.eerussianguy.firmalife.client.screen.StovetopGrillScreen; +import com.eerussianguy.firmalife.client.screen.StovetopPotScreen; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.color.block.BlockColor; @@ -67,7 +69,7 @@ public static void clientSetup(FMLClientSetupEvent event) FLBlocks.CURED_OVEN_CHIMNEY, FLBlocks.QUAD_PLANTER, FLBlocks.LARGE_PLANTER, FLBlocks.HANGING_PLANTER, FLBlocks.BONSAI_PLANTER, FLBlocks.IRON_COMPOSTER, FLBlocks.COMPOST_JAR, FLBlocks.HONEY_JAR, FLBlocks.ROTTEN_COMPOST_JAR, FLBlocks.GUANO_JAR, FLBlocks.CHEDDAR_WHEEL, FLBlocks.RAJYA_METOK_WHEEL, FLBlocks.CHEVRE_WHEEL, FLBlocks.SHOSHA_WHEEL, FLBlocks.FETA_WHEEL, FLBlocks.GOUDA_WHEEL, FLBlocks.SMALL_CHROMITE, - FLBlocks.MIXING_BOWL, FLBlocks.BUTTERFLY_GRASS, FLBlocks.SPRINKLER, FLBlocks.DRIBBLER, FLBlocks.VAT, FLBlocks.HYDROPONIC_PLANTER + FLBlocks.MIXING_BOWL, FLBlocks.BUTTERFLY_GRASS, FLBlocks.SPRINKLER, FLBlocks.DRIBBLER, FLBlocks.VAT, FLBlocks.HYDROPONIC_PLANTER, FLBlocks.STOVETOP_GRILL, FLBlocks.STOVETOP_POT ).forEach(reg -> ItemBlockRenderTypes.setRenderLayer(reg.get(), cutout)); ItemBlockRenderTypes.setRenderLayer(FLBlocks.SOLAR_DRIER.get(), translucent); @@ -88,6 +90,8 @@ public static void clientSetup(FMLClientSetupEvent event) event.enqueueWork(() -> { MenuScreens.register(FLContainerTypes.BEEHIVE.get(), BeehiveScreen::new); + MenuScreens.register(FLContainerTypes.STOVETOP_GRILL.get(), StovetopGrillScreen::new); + MenuScreens.register(FLContainerTypes.STOVETOP_POT.get(), StovetopPotScreen::new); MenuScreens.register(FLContainerTypes.PUMPKIN.get(), KnappingScreen::new); TFCItems.FOOD.forEach((food, item) -> { @@ -149,6 +153,8 @@ public static void registerEntityRenderers(EntityRenderersEvent.RegisterRenderer event.registerBlockEntityRenderer(FLBlockEntities.MIXING_BOWL.get(), ctx -> new MixingBowlBlockEntityRenderer()); event.registerBlockEntityRenderer(FLBlockEntities.HANGER.get(), ctx -> new HangerBlockEntityRenderer()); event.registerBlockEntityRenderer(FLBlockEntities.FOOD_SHELF.get(), ctx -> new FoodShelfBlockEntityRenderer()); + event.registerBlockEntityRenderer(FLBlockEntities.STOVETOP_GRILL.get(), ctx -> new StovetopGrillBlockEntityRenderer()); + event.registerBlockEntityRenderer(FLBlockEntities.STOVETOP_POT.get(), ctx -> new StovetopPotBlockEntityRenderer()); event.registerEntityRenderer(FLEntities.SEED_BALL.get(), ThrownItemRenderer::new); } diff --git a/src/main/java/com/eerussianguy/firmalife/client/render/StovetopGrillBlockEntityRenderer.java b/src/main/java/com/eerussianguy/firmalife/client/render/StovetopGrillBlockEntityRenderer.java new file mode 100644 index 00000000..ae8acac7 --- /dev/null +++ b/src/main/java/com/eerussianguy/firmalife/client/render/StovetopGrillBlockEntityRenderer.java @@ -0,0 +1,48 @@ +package com.eerussianguy.firmalife.client.render; + +import com.eerussianguy.firmalife.common.blockentities.StovetopGrillBlockEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.world.item.ItemStack; + +import net.dries007.tfc.client.RenderHelpers; +import net.dries007.tfc.common.capabilities.Capabilities; + +public class StovetopGrillBlockEntityRenderer implements BlockEntityRenderer +{ + @Override + public void render(StovetopGrillBlockEntity grill, float partialTicks, PoseStack poseStack, MultiBufferSource buffer, int combinedLight, int combinedOverlay) + { + grill.getCapability(Capabilities.ITEM).ifPresent(cap -> { + for (int i = 0; i < StovetopGrillBlockEntity.SLOTS; i++) + { + ItemStack item = cap.getStackInSlot(i); + if (!item.isEmpty()) + { + float yOffset = 1f / 16; + poseStack.pushPose(); + poseStack.translate(0.3, 0.003125D + yOffset, 0.28); + poseStack.scale(0.3f, 0.3f, 0.3f); + poseStack.mulPose(RenderHelpers.rotateDegreesX(90F)); + poseStack.mulPose(RenderHelpers.rotateDegreesZ(180F)); + + float translateAmount = -1.4F; + if (i == 1 || i == 3) + { + poseStack.translate(translateAmount, 0, 0); + } + if (i == 2 || i == 3) + { + poseStack.translate(0, translateAmount, 0); + } + + Minecraft.getInstance().getItemRenderer().renderStatic(item, ItemTransforms.TransformType.FIXED, combinedLight, combinedOverlay, poseStack, buffer, 0); + poseStack.popPose(); + } + } + }); + } +} diff --git a/src/main/java/com/eerussianguy/firmalife/client/render/StovetopPotBlockEntityRenderer.java b/src/main/java/com/eerussianguy/firmalife/client/render/StovetopPotBlockEntityRenderer.java new file mode 100644 index 00000000..3da2576f --- /dev/null +++ b/src/main/java/com/eerussianguy/firmalife/client/render/StovetopPotBlockEntityRenderer.java @@ -0,0 +1,58 @@ +package com.eerussianguy.firmalife.client.render; + +import com.eerussianguy.firmalife.common.blockentities.StovetopPotBlockEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.material.Fluids; +import net.minecraftforge.fluids.FluidStack; + +import net.dries007.tfc.client.RenderHelpers; +import net.dries007.tfc.common.capabilities.Capabilities; +import net.dries007.tfc.common.fluids.TFCFluids; + +public class StovetopPotBlockEntityRenderer implements BlockEntityRenderer +{ + @Override + public void render(StovetopPotBlockEntity pot, float partialTicks, PoseStack poseStack, MultiBufferSource buffer, int combinedLight, int combinedOverlay) + { + if (pot.getLevel() == null) return; + + FluidStack fluidStack = pot.getCapability(Capabilities.FLUID).map(cap -> cap.getFluidInTank(0)).orElse(FluidStack.EMPTY); + if (pot.hasOutput()) + { + fluidStack = new FluidStack(Fluids.WATER, 1000); + } + if (!fluidStack.isEmpty()) + { + final int color = pot.hasOutput() ? (TFCFluids.ALPHA_MASK | 0xA64214) : RenderHelpers.getFluidColor(fluidStack); + RenderHelpers.renderFluidFace(poseStack, fluidStack, buffer, color, 0.3125F, 0.3125F, 0.6875F, 0.6875F, 5f / 16, combinedOverlay, combinedLight); + } + + pot.getCapability(Capabilities.ITEM).ifPresent(cap -> { + int ordinal = 0; + for (int slot = 0; slot < StovetopPotBlockEntity.SLOTS; slot++) + { + ItemStack item = cap.getStackInSlot(slot); + if (!item.isEmpty()) + { + float yOffset = 1f / 16; + poseStack.pushPose(); + poseStack.translate(0.5, 0.003125D + yOffset, 0.5); + poseStack.scale(0.3f, 0.3f, 0.3f); + poseStack.mulPose(RenderHelpers.rotateDegreesX(90F)); + poseStack.mulPose(RenderHelpers.rotateDegreesZ(180F)); + + ordinal++; + poseStack.translate(0, 0, -0.12F * ordinal); + + Minecraft.getInstance().getItemRenderer().renderStatic(item, ItemTransforms.TransformType.FIXED, combinedLight, combinedOverlay, poseStack, buffer, 0); + poseStack.popPose(); + } + } + }); + } +} diff --git a/src/main/java/com/eerussianguy/firmalife/client/screen/StovetopGrillScreen.java b/src/main/java/com/eerussianguy/firmalife/client/screen/StovetopGrillScreen.java new file mode 100644 index 00000000..4c5eb427 --- /dev/null +++ b/src/main/java/com/eerussianguy/firmalife/client/screen/StovetopGrillScreen.java @@ -0,0 +1,29 @@ +package com.eerussianguy.firmalife.client.screen; + +import com.eerussianguy.firmalife.common.container.StovetopGrillContainer; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; + +import net.dries007.tfc.client.screen.TFCContainerScreen; +import net.dries007.tfc.common.capabilities.heat.Heat; + +public class StovetopGrillScreen extends TFCContainerScreen +{ + public StovetopGrillScreen(StovetopGrillContainer container, Inventory playerInventory, Component name) + { + super(container, playerInventory, name, INVENTORY_2x2); + } + + + @Override + protected void renderLabels(PoseStack poseStack, int mouseX, int mouseY) + { + super.renderLabels(poseStack, mouseX, mouseY); + Heat heat = Heat.getHeat(menu.getBlockEntity().getTemperature()); + if (heat != null) + { + drawCenteredLine(poseStack, heat.getDisplayName(), 64); + } + } +} diff --git a/src/main/java/com/eerussianguy/firmalife/client/screen/StovetopPotScreen.java b/src/main/java/com/eerussianguy/firmalife/client/screen/StovetopPotScreen.java new file mode 100644 index 00000000..ba02c2ac --- /dev/null +++ b/src/main/java/com/eerussianguy/firmalife/client/screen/StovetopPotScreen.java @@ -0,0 +1,28 @@ +package com.eerussianguy.firmalife.client.screen; + +import com.eerussianguy.firmalife.common.container.StovetopPotContainer; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; + +import net.dries007.tfc.client.screen.TFCContainerScreen; +import net.dries007.tfc.common.capabilities.heat.Heat; + +public class StovetopPotScreen extends TFCContainerScreen +{ + public StovetopPotScreen(StovetopPotContainer container, Inventory playerInventory, Component name) + { + super(container, playerInventory, name, INVENTORY_2x2); + } + + @Override + protected void renderLabels(PoseStack poseStack, int mouseX, int mouseY) + { + super.renderLabels(poseStack, mouseX, mouseY); + Heat heat = Heat.getHeat(menu.getBlockEntity().getTemperature()); + if (heat != null) + { + drawCenteredLine(poseStack, heat.getDisplayName(), 64); + } + } +} diff --git a/src/main/java/com/eerussianguy/firmalife/client/screen/package-info.java b/src/main/java/com/eerussianguy/firmalife/client/screen/package-info.java new file mode 100644 index 00000000..cc050451 --- /dev/null +++ b/src/main/java/com/eerussianguy/firmalife/client/screen/package-info.java @@ -0,0 +1,14 @@ +/* + * Licensed under the EUPL, Version 1.2. + * You may obtain a copy of the Licence at: + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + */ + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +@FieldsAreNonnullByDefault +package com.eerussianguy.firmalife.client.screen; + +import javax.annotation.ParametersAreNonnullByDefault; +import net.minecraft.FieldsAreNonnullByDefault; +import net.minecraft.MethodsReturnNonnullByDefault; diff --git a/src/main/java/com/eerussianguy/firmalife/common/FLTags.java b/src/main/java/com/eerussianguy/firmalife/common/FLTags.java index dfe4f9ea..526d9398 100644 --- a/src/main/java/com/eerussianguy/firmalife/common/FLTags.java +++ b/src/main/java/com/eerussianguy/firmalife/common/FLTags.java @@ -43,6 +43,7 @@ public static class Items public static final TagKey PIE_PANS = create("pie_pans"); public static final TagKey CONTAINS_PIE_PAN = create("contains_pie_pan"); public static final TagKey CAN_BE_HUNG = create("can_be_hung"); + public static final TagKey USABLE_IN_STOVETOP_SOUP = create("usable_in_stovetop_soup"); private static TagKey create(String id) { diff --git a/src/main/java/com/eerussianguy/firmalife/common/blockentities/ApplianceBlockEntity.java b/src/main/java/com/eerussianguy/firmalife/common/blockentities/ApplianceBlockEntity.java new file mode 100644 index 00000000..8135d9c1 --- /dev/null +++ b/src/main/java/com/eerussianguy/firmalife/common/blockentities/ApplianceBlockEntity.java @@ -0,0 +1,193 @@ +package com.eerussianguy.firmalife.common.blockentities; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.INBTSerializable; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.ItemStackHandler; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import net.dries007.tfc.common.blockentities.InventoryBlockEntity; +import net.dries007.tfc.common.blockentities.TickableInventoryBlockEntity; +import net.dries007.tfc.common.capabilities.DelegateItemHandler; +import net.dries007.tfc.common.capabilities.InventoryItemHandler; +import net.dries007.tfc.common.capabilities.SidedHandler; +import net.dries007.tfc.common.capabilities.heat.HeatCapability; +import net.dries007.tfc.common.capabilities.heat.IHeatBlock; +import net.dries007.tfc.common.recipes.inventory.EmptyInventory; +import net.dries007.tfc.util.calendar.Calendars; +import net.dries007.tfc.util.calendar.ICalendarTickable; + +public abstract class ApplianceBlockEntity & IHeatBlock> extends TickableInventoryBlockEntity implements ICalendarTickable +{ + private long lastUpdateTick; + protected float temperature = 0; + protected float targetTemperature = 0; + protected int targetTemperatureStabilityTicks = 0; + + private final SidedHandler.Noop sidedHeat; + + public ApplianceBlockEntity(BlockEntityType type, BlockPos pos, BlockState state, InventoryFactory inventoryFactory, Component name) + { + super(type, pos, state, inventoryFactory, name); + lastUpdateTick = Calendars.SERVER.getTicks(); + + sidedHeat = new SidedHandler.Noop<>(inventory); + } + + public void tickTemperature() + { + if (temperature != targetTemperature) + { + temperature = HeatCapability.adjustTempTowards(temperature, targetTemperature); + onTemperatureAdjusted(); + } + if (targetTemperatureStabilityTicks > 0) + { + targetTemperatureStabilityTicks--; + } + if (targetTemperature > 0 && targetTemperatureStabilityTicks == 0) + { + // target temperature decays constantly, since it is set externally. As long as we don't consider ourselves 'stable' + targetTemperature = HeatCapability.adjustTempTowards(targetTemperature, 0); + } + } + + public void onTemperatureAdjusted() {} + + @Override + public void onCalendarUpdate(long ticks) + { + assert level != null; + // Crucible has no fuel to consume, but it does drop the internal target and temperature over time. + final boolean wasHot = temperature > 0; + targetTemperature = HeatCapability.adjustTempTowards(targetTemperature, 0, ticks); + temperature = HeatCapability.adjustTempTowards(temperature, targetTemperature, ticks); + if (wasHot && temperature == 0) + { + ranOutDueToCalendar(); + markForSync(); + } + } + + public void ranOutDueToCalendar() {} + + @Override + public long getLastUpdateTick() + { + return lastUpdateTick; + } + + @Override + public void setLastUpdateTick(long tick) + { + lastUpdateTick = tick; + } + + public float getTemperature() + { + return temperature; + } + + @Override + public void loadAdditional(CompoundTag nbt) + { + lastUpdateTick = nbt.getLong("lastTick"); + temperature = nbt.getFloat("temperature"); + targetTemperature = nbt.getFloat("targetTemperature"); + targetTemperatureStabilityTicks = nbt.getInt("targetTemperatureStabilityTicks"); + super.loadAdditional(nbt); + } + + @Override + public void saveAdditional(CompoundTag nbt) + { + nbt.putLong("lastTick", lastUpdateTick); + nbt.putFloat("temperature", temperature); + nbt.putFloat("targetTemperature", targetTemperature); + nbt.putInt("targetTemperatureStabilityTicks", targetTemperatureStabilityTicks); + super.saveAdditional(nbt); + } + + @NotNull + @Override + public LazyOptional getCapability(Capability cap, @Nullable Direction side) + { + if (cap == HeatCapability.BLOCK_CAPABILITY) + { + return sidedHeat.getSidedHandler(side).cast(); + } + return super.getCapability(cap, side); + } + + public static class ApplianceInventory implements EmptyInventory, DelegateItemHandler, INBTSerializable, CrucibleLikeHeatBlock + { + private final ApplianceBlockEntity appliance; + protected final ItemStackHandler inventory; + + public ApplianceInventory(InventoryBlockEntity entity, int slots) + { + this.appliance = (ApplianceBlockEntity) entity; + this.inventory = new InventoryItemHandler(entity, slots); + } + + @Override + public IItemHandlerModifiable getItemHandler() + { + return inventory; + } + + @Override + public CompoundTag serializeNBT() + { + CompoundTag nbt = new CompoundTag(); + nbt.put("inventory", inventory.serializeNBT()); + return nbt; + } + + @Override + public void deserializeNBT(CompoundTag nbt) + { + inventory.deserializeNBT(nbt.getCompound("inventory")); + } + + @Override + public float getTemperature() + { + return appliance.temperature; + } + + @Override + public void setTargetTemperature(float temp) + { + appliance.targetTemperature = temp; + } + + @Override + public float getTargetTemperature() + { + return appliance.targetTemperature; + } + + @Override + public void resetStability() + { + appliance.targetTemperatureStabilityTicks = OvenTopBlockEntity.TARGET_TEMPERATURE_STABILITY_TICKS; + appliance.markForSync(); + } + + @Override + public void setTemperature(float temperature) + { + CrucibleLikeHeatBlock.super.setTemperature(temperature); + appliance.temperature = temperature; + } + } +} diff --git a/src/main/java/com/eerussianguy/firmalife/common/blockentities/BoilingBlockEntity.java b/src/main/java/com/eerussianguy/firmalife/common/blockentities/BoilingBlockEntity.java new file mode 100644 index 00000000..16789aed --- /dev/null +++ b/src/main/java/com/eerussianguy/firmalife/common/blockentities/BoilingBlockEntity.java @@ -0,0 +1,131 @@ +package com.eerussianguy.firmalife.common.blockentities; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.INBTSerializable; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.items.IItemHandlerModifiable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import net.dries007.tfc.common.blockentities.InventoryBlockEntity; +import net.dries007.tfc.common.capabilities.Capabilities; +import net.dries007.tfc.common.capabilities.DelegateFluidHandler; +import net.dries007.tfc.common.capabilities.FluidTankCallback; +import net.dries007.tfc.common.capabilities.InventoryFluidTank; +import net.dries007.tfc.common.capabilities.PartialFluidHandler; +import net.dries007.tfc.common.capabilities.SidedHandler; +import net.dries007.tfc.common.capabilities.heat.IHeatBlock; +import net.dries007.tfc.util.calendar.ICalendarTickable; + +public abstract class BoilingBlockEntity & IHeatBlock & IFluidHandler> extends ApplianceBlockEntity implements ICalendarTickable, FluidTankCallback +{ + protected int boilingTicks = 0; + protected boolean needsRecipeUpdate = true; + private final SidedHandler.Builder sidedFluidInventory; + + public BoilingBlockEntity(BlockEntityType type, BlockPos pos, BlockState state, InventoryFactory inventoryFactory, Component name) + { + super(type, pos, state, inventoryFactory, name); + + sidedFluidInventory = new SidedHandler.Builder<>(inventory); + sidedFluidInventory.on(new PartialFluidHandler(inventory).insert(), Direction.UP) + .on(new PartialFluidHandler(inventory).extract(), Direction.Plane.HORIZONTAL); + } + + @NotNull + @Override + public LazyOptional getCapability(Capability cap, @Nullable Direction side) + { + if (cap == Capabilities.FLUID) + { + return sidedFluidInventory.getSidedHandler(side).cast(); + } + return super.getCapability(cap, side); + } + + @Override + public void ranOutDueToCalendar() + { + boilingTicks = 0; + } + + @Override + public void fluidTankChanged() + { + FluidTankCallback.super.fluidTankChanged(); + needsRecipeUpdate = true; + } + + @Override + public void setAndUpdateSlots(int slot) + { + super.setAndUpdateSlots(slot); + needsRecipeUpdate = true; + } + + @Override + public void loadAdditional(CompoundTag nbt) + { + boilingTicks = nbt.getInt("boilingTicks"); + needsRecipeUpdate = true; + super.loadAdditional(nbt); + } + + @Override + public void saveAdditional(CompoundTag nbt) + { + nbt.putInt("boilingTicks", boilingTicks); + super.saveAdditional(nbt); + } + + abstract boolean isBoiling(); + + public static class BoilingInventory extends ApplianceInventory implements DelegateFluidHandler, FluidTankCallback + { + protected final InventoryFluidTank tank; + private final BoilingBlockEntity boiling; + + public BoilingInventory(InventoryBlockEntity entity, int slots, InventoryFluidTank tank) + { + super(entity, slots); + this.tank = tank; + this.boiling = (BoilingBlockEntity) entity; + } + + @Override + public IFluidHandler getFluidHandler() + { + return tank; + } + + @NotNull + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) + { + return boiling.isBoiling() ? ItemStack.EMPTY : inventory.extractItem(slot, amount, simulate); + } + + @Override + public CompoundTag serializeNBT() + { + CompoundTag nbt = super.serializeNBT(); + nbt.put("tank", tank.writeToNBT(new CompoundTag())); + return nbt; + } + + @Override + public void deserializeNBT(CompoundTag nbt) + { + super.deserializeNBT(nbt); + tank.readFromNBT(nbt.getCompound("tank")); + } + } +} diff --git a/src/main/java/com/eerussianguy/firmalife/common/blockentities/FLBlockEntities.java b/src/main/java/com/eerussianguy/firmalife/common/blockentities/FLBlockEntities.java index ea612073..2fc9c213 100644 --- a/src/main/java/com/eerussianguy/firmalife/common/blockentities/FLBlockEntities.java +++ b/src/main/java/com/eerussianguy/firmalife/common/blockentities/FLBlockEntities.java @@ -3,6 +3,7 @@ import java.util.function.Supplier; import java.util.stream.Stream; +import com.eerussianguy.firmalife.common.blocks.StovetopPotBlock; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; @@ -42,6 +43,8 @@ public class FLBlockEntities public static final RegistryObject> HANGER = register("hanger", HangerBlockEntity::new, Stream.of(FLBlocks.HANGERS.values()).>flatMap(Helpers::flatten)); public static final RegistryObject> VAT = register("vat", VatBlockEntity::new, FLBlocks.VAT); public static final RegistryObject> ASHTRAY = register("ashtray", AshTrayBlockEntity::new, FLBlocks.ASHTRAY); + public static final RegistryObject> STOVETOP_GRILL = register("stovetop_grill", StovetopGrillBlockEntity::new, FLBlocks.STOVETOP_GRILL); + public static final RegistryObject> STOVETOP_POT = register("stovetop_pot", StovetopPotBlockEntity::new, FLBlocks.STOVETOP_POT); public static final RegistryObject> LARGE_PLANTER = register("large_planter", LargePlanterBlockEntity::new, FLBlocks.LARGE_PLANTER); public static final RegistryObject> BONSAI_PLANTER = register("bonsai_planter", BonsaiPlanterBlockEntity::new, FLBlocks.BONSAI_PLANTER); diff --git a/src/main/java/com/eerussianguy/firmalife/common/blockentities/OvenTopBlockEntity.java b/src/main/java/com/eerussianguy/firmalife/common/blockentities/OvenTopBlockEntity.java index a1e0f281..077c0dfc 100644 --- a/src/main/java/com/eerussianguy/firmalife/common/blockentities/OvenTopBlockEntity.java +++ b/src/main/java/com/eerussianguy/firmalife/common/blockentities/OvenTopBlockEntity.java @@ -7,35 +7,22 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.INBTSerializable; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.IItemHandlerModifiable; import com.eerussianguy.firmalife.common.FLHelpers; import com.eerussianguy.firmalife.common.blocks.ICure; -import com.eerussianguy.firmalife.common.blocks.OvenBottomBlock; import com.eerussianguy.firmalife.common.items.FLFoodTraits; import com.eerussianguy.firmalife.common.recipes.WrappedHeatingRecipe; import net.dries007.tfc.common.blockentities.InventoryBlockEntity; -import net.dries007.tfc.common.blockentities.TickableInventoryBlockEntity; -import net.dries007.tfc.common.capabilities.DelegateItemHandler; -import net.dries007.tfc.common.capabilities.InventoryItemHandler; -import net.dries007.tfc.common.capabilities.SidedHandler; import net.dries007.tfc.common.capabilities.food.FoodCapability; import net.dries007.tfc.common.capabilities.heat.HeatCapability; -import net.dries007.tfc.common.capabilities.heat.IHeatBlock; import net.dries007.tfc.common.recipes.inventory.ItemStackInventory; import net.dries007.tfc.util.Helpers; -import net.dries007.tfc.util.calendar.Calendars; import net.dries007.tfc.util.calendar.ICalendarTickable; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** * Works like a crucible but with a delay on producing the heating recipes. */ -public class OvenTopBlockEntity extends TickableInventoryBlockEntity implements ICalendarTickable, OvenLike +public class OvenTopBlockEntity extends ApplianceBlockEntity implements ICalendarTickable, OvenLike { public static void cure(Level level, BlockState oldState, BlockState newState, BlockPos pos) { @@ -71,34 +58,13 @@ public static void serverTick(Level level, BlockPos pos, BlockState state, OvenT oven.checkForLastTickSync(); oven.checkForCalendarUpdate(); - if (oven.temperature != oven.targetTemperature) - { - oven.temperature = HeatCapability.adjustTempTowards(oven.temperature, oven.targetTemperature); - - for (Direction d : Direction.Plane.HORIZONTAL) - { - if (level.getBlockEntity(pos.relative(d)) instanceof OvenTopBlockEntity otherOven) - { - otherOven.getCapability(HeatCapability.BLOCK_CAPABILITY).ifPresent(cap -> cap.setTemperatureIfWarmer(oven.temperature - 100f)); - } - } - } final boolean cured = state.getBlock() instanceof ICure cure && cure.isCured(); final int updateInterval = 40; if (level.getGameTime() % updateInterval == 0) { OvenLike.regularBlockUpdate(level, pos, state, oven, cured, updateInterval); } - - if (oven.targetTemperatureStabilityTicks > 0) - { - oven.targetTemperatureStabilityTicks--; - } - if (oven.targetTemperature > 0 && oven.targetTemperatureStabilityTicks == 0) - { - // target temperature decays constantly, since it is set externally. As long as we don't consider ourselves 'stable' - oven.targetTemperature = HeatCapability.adjustTempTowards(oven.targetTemperature, 0); - } + oven.tickTemperature(); if (!cured) return; for (int i = SLOT_INPUT_START; i <= SLOT_INPUT_END; i++) @@ -143,13 +109,6 @@ public static void serverTick(Level level, BlockPos pos, BlockState state, OvenT public static final int SLOT_INPUT_START = 0; public static final int TARGET_TEMPERATURE_STABILITY_TICKS = 400; - private final SidedHandler.Noop sidedHeat; - - - float temperature; - private float targetTemperature; - private int targetTemperatureStabilityTicks; - private long lastPlayerTick; private boolean needsRecipeUpdate; private final WrappedHeatingRecipe[] cachedRecipes; private int[] cookTicks; @@ -158,23 +117,16 @@ public static void serverTick(Level level, BlockPos pos, BlockState state, OvenT public OvenTopBlockEntity(BlockPos pos, BlockState state) { super(FLBlockEntities.OVEN_TOP.get(), pos, state, OvenInventory::new, FLHelpers.blockEntityName("oven_top")); - temperature = targetTemperature = targetTemperatureStabilityTicks = cureTicks = 0; - lastPlayerTick = Calendars.SERVER.getTicks(); + cureTicks = 0; cachedRecipes = new WrappedHeatingRecipe[4]; cookTicks = new int[] {0, 0, 0, 0}; - - sidedHeat = new SidedHandler.Noop<>(inventory); } @Override public void loadAdditional(CompoundTag nbt) { - temperature = nbt.getFloat("temperature"); - targetTemperature = nbt.getFloat("targetTemperature"); - targetTemperatureStabilityTicks = nbt.getInt("targetTemperatureStabilityTicks"); cookTicks = nbt.getIntArray("cookTicks"); cureTicks = nbt.getInt("cureTicks"); - lastPlayerTick = nbt.getLong("lastTick"); needsRecipeUpdate = true; super.loadAdditional(nbt); } @@ -182,21 +134,11 @@ public void loadAdditional(CompoundTag nbt) @Override public void saveAdditional(CompoundTag nbt) { - nbt.putFloat("temperature", temperature); - nbt.putFloat("targetTemperature", targetTemperature); - nbt.putInt("targetTemperatureStabilityTicks", targetTemperatureStabilityTicks); nbt.putIntArray("cookTicks", cookTicks); nbt.putInt("cureTicks", cureTicks); - nbt.putLong("lastTick", lastPlayerTick); super.saveAdditional(nbt); } - @Override - public float getTemperature() - { - return temperature; - } - @Override public int getCureTicks() { @@ -209,36 +151,25 @@ public void addCureTicks(int ticks) cureTicks += ticks; } - @NotNull @Override - public LazyOptional getCapability(Capability cap, @Nullable Direction side) + public void ranOutDueToCalendar() { - if (cap == HeatCapability.BLOCK_CAPABILITY) + for (int i = 0; i < SLOTS; i++) { - return sidedHeat.getSidedHandler(side).cast(); + cookTicks[i] = 0; } - return super.getCapability(cap, side); - } - - @Override - public void onCalendarUpdate(long ticks) - { - assert level != null; - // Crucible has no fuel to consume, but it does drop the internal target and temperature over time. - targetTemperature = HeatCapability.adjustTempTowards(targetTemperature, 0, ticks); - temperature = HeatCapability.adjustTempTowards(temperature, targetTemperature, ticks); } @Override - public long getLastUpdateTick() + public void onTemperatureAdjusted() { - return lastPlayerTick; - } - - @Override - public void setLastUpdateTick(long ticks) - { - lastPlayerTick = ticks; + for (Direction d : Direction.Plane.HORIZONTAL) + { + if (level.getBlockEntity(getBlockPos().relative(d)) instanceof OvenTopBlockEntity otherOven) + { + otherOven.getCapability(HeatCapability.BLOCK_CAPABILITY).ifPresent(cap -> cap.setTemperatureIfWarmer(temperature - 100f)); + } + } } @Override @@ -251,7 +182,7 @@ public void setAndUpdateSlots(int slot) @Override public boolean isItemValid(int slot, ItemStack stack) { - return stack.getCapability(HeatCapability.CAPABILITY).isPresent(); + return Helpers.mightHaveCapability(stack, HeatCapability.CAPABILITY); } @Override @@ -311,67 +242,11 @@ public int getTicksLeft(int slot) return -1; } - static class OvenInventory implements DelegateItemHandler, CrucibleLikeHeatBlock, INBTSerializable + public static class OvenInventory extends ApplianceBlockEntity.ApplianceInventory { - private final OvenTopBlockEntity oven; - private final InventoryItemHandler inventory; - - public OvenInventory(InventoryBlockEntity blockEntity) - { - this.oven = (OvenTopBlockEntity) blockEntity; - this.inventory = new InventoryItemHandler(blockEntity, SLOTS); - } - - @Override - public IItemHandlerModifiable getItemHandler() - { - return inventory; - } - - @Override - public float getTemperature() - { - return oven.temperature; - } - - @Override - public void setTargetTemperature(float temp) - { - oven.targetTemperature = temp; - } - - @Override - public float getTargetTemperature() - { - return oven.targetTemperature; - } - - @Override - public void setTemperature(float temperature) - { - CrucibleLikeHeatBlock.super.setTemperature(temperature); - oven.temperature = temperature; - } - - @Override - public void resetStability() - { - oven.targetTemperatureStabilityTicks = TARGET_TEMPERATURE_STABILITY_TICKS; - oven.markForSync(); - } - - @Override - public CompoundTag serializeNBT() - { - final CompoundTag nbt = new CompoundTag(); - nbt.put("inventory", inventory.serializeNBT()); - return nbt; - } - - @Override - public void deserializeNBT(CompoundTag nbt) + public OvenInventory(InventoryBlockEntity entity) { - inventory.deserializeNBT(nbt.getCompound("inventory")); + super(entity, SLOTS); } } } diff --git a/src/main/java/com/eerussianguy/firmalife/common/blockentities/StovetopGrillBlockEntity.java b/src/main/java/com/eerussianguy/firmalife/common/blockentities/StovetopGrillBlockEntity.java new file mode 100644 index 00000000..3824739f --- /dev/null +++ b/src/main/java/com/eerussianguy/firmalife/common/blockentities/StovetopGrillBlockEntity.java @@ -0,0 +1,125 @@ +package com.eerussianguy.firmalife.common.blockentities; + +import com.eerussianguy.firmalife.common.FLHelpers; +import com.eerussianguy.firmalife.common.container.StovetopGrillContainer; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +import net.dries007.tfc.common.blockentities.InventoryBlockEntity; +import net.dries007.tfc.common.capabilities.PartialItemHandler; +import net.dries007.tfc.common.capabilities.food.FoodCapability; +import net.dries007.tfc.common.capabilities.food.FoodTraits; +import net.dries007.tfc.common.capabilities.heat.HeatCapability; +import net.dries007.tfc.common.recipes.HeatingRecipe; +import net.dries007.tfc.common.recipes.inventory.ItemStackInventory; +import net.dries007.tfc.util.Helpers; + +public class StovetopGrillBlockEntity extends ApplianceBlockEntity +{ + public static void serverTick(Level level, BlockPos pos, BlockState state, StovetopGrillBlockEntity grill) + { + grill.checkForLastTickSync(); + grill.checkForCalendarUpdate(); + + if (grill.needsRecipeUpdate) + { + grill.updateCachedRecipe(); + } + + grill.tickTemperature(); + grill.handleCooking(); + } + + public static final int SLOTS = 4; + + private final HeatingRecipe[] cachedRecipes; + private boolean needsRecipeUpdate = true; + + public StovetopGrillBlockEntity(BlockPos pos, BlockState state) + { + super(FLBlockEntities.STOVETOP_GRILL.get(), pos, state, GrillInventory::new, FLHelpers.blockEntityName("stovetop_grill")); + + sidedInventory + .on(new PartialItemHandler(inventory).insert(0, 1, 2, 3), Direction.UP) + .on(new PartialItemHandler(inventory).extract(0, 1, 2, 3), Direction.Plane.HORIZONTAL); + cachedRecipes = new HeatingRecipe[SLOTS]; + } + + @Override + public @Nullable AbstractContainerMenu createMenu(int containerId, Inventory inventory, Player player) + { + return StovetopGrillContainer.create(this, inventory, containerId); + } + + @Override + public int getSlotStackLimit(int slot) + { + return 1; + } + + @Override + public boolean isItemValid(int slot, ItemStack stack) + { + return Helpers.mightHaveCapability(stack, HeatCapability.CAPABILITY); + } + + @Override + public void loadAdditional(CompoundTag nbt) + { + super.loadAdditional(nbt); + needsRecipeUpdate = true; + } + + @Override + public void setAndUpdateSlots(int slot) + { + super.setAndUpdateSlots(slot); + needsRecipeUpdate = true; + } + + protected void handleCooking() + { + for (int slot = 0; slot < SLOTS; slot++) + { + final ItemStack inputStack = inventory.getStackInSlot(slot); + final int finalSlot = slot; + inputStack.getCapability(HeatCapability.CAPABILITY, null).ifPresent(cap -> { + HeatCapability.addTemp(cap, temperature); + final HeatingRecipe recipe = cachedRecipes[finalSlot]; + if (recipe != null && recipe.isValidTemperature(cap.getTemperature())) + { + ItemStack output = recipe.assemble(new ItemStackInventory(inputStack)); + FoodCapability.applyTrait(output, FoodTraits.WOOD_GRILLED); + inventory.setStackInSlot(finalSlot, output); + markForSync(); + } + }); + } + } + + protected void updateCachedRecipe() + { + assert level != null; + for (int slot = 0; slot < SLOTS; slot++) + { + final ItemStack stack = inventory.getStackInSlot(slot); + cachedRecipes[slot] = stack.isEmpty() ? null : HeatingRecipe.getRecipe(new ItemStackInventory(stack)); + } + } + + public static class GrillInventory extends ApplianceInventory + { + public GrillInventory(InventoryBlockEntity entity) + { + super(entity, SLOTS); + } + } +} diff --git a/src/main/java/com/eerussianguy/firmalife/common/blockentities/StovetopPotBlockEntity.java b/src/main/java/com/eerussianguy/firmalife/common/blockentities/StovetopPotBlockEntity.java new file mode 100644 index 00000000..ec238280 --- /dev/null +++ b/src/main/java/com/eerussianguy/firmalife/common/blockentities/StovetopPotBlockEntity.java @@ -0,0 +1,256 @@ +package com.eerussianguy.firmalife.common.blockentities; + +import com.eerussianguy.firmalife.common.FLHelpers; +import com.eerussianguy.firmalife.common.FLTags; +import com.eerussianguy.firmalife.common.container.StovetopPotContainer; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Fluids; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.items.ItemHandlerHelper; +import org.jetbrains.annotations.Nullable; + +import net.dries007.tfc.common.TFCTags; +import net.dries007.tfc.common.blockentities.InventoryBlockEntity; +import net.dries007.tfc.common.capabilities.InventoryFluidTank; +import net.dries007.tfc.common.capabilities.PartialItemHandler; +import net.dries007.tfc.common.capabilities.food.FoodCapability; +import net.dries007.tfc.common.capabilities.food.FoodData; +import net.dries007.tfc.common.capabilities.food.IFood; +import net.dries007.tfc.common.capabilities.food.Nutrient; +import net.dries007.tfc.common.items.DynamicBowlFood; +import net.dries007.tfc.common.items.TFCItems; +import net.dries007.tfc.common.recipes.SoupPotRecipe; +import net.dries007.tfc.util.Helpers; + +public class StovetopPotBlockEntity extends BoilingBlockEntity +{ + public static void serverTick(Level level, BlockPos pos, BlockState state, StovetopPotBlockEntity pot) + { + pot.checkForLastTickSync(); + pot.checkForCalendarUpdate(); + + if (pot.needsRecipeUpdate) + { + pot.updateCachedRecipe(); + } + + pot.tickTemperature(); + pot.handleCooking(); + } + + public static final int SLOTS = 4; + private static final int DURATION = 1000; + private static final float MIN_TEMP = 500f; + + private boolean hasRecipe = false; + private ItemStack soupStack = ItemStack.EMPTY; + + public StovetopPotBlockEntity(BlockPos pos, BlockState state) + { + super(FLBlockEntities.STOVETOP_POT.get(), pos, state, StovetopPotInventory::new, FLHelpers.blockEntityName("stovetop_pot")); + sidedInventory.on(new PartialItemHandler(inventory).insert(), Direction.Plane.HORIZONTAL); + } + + @Override + public @Nullable AbstractContainerMenu createMenu(int containerId, Inventory inventory, Player player) + { + return StovetopPotContainer.create(this, inventory, containerId); + } + + public boolean hasOutput() + { + return !soupStack.isEmpty(); + } + + public void updateCachedRecipe() + { + if (inventory.getFluidInTank(0).getAmount() >= 100 && temperature > MIN_TEMP) + { + int found = 0; + for (ItemStack stack : Helpers.iterate(inventory)) + { + if (!stack.isEmpty()) + { + found++; + } + } + if (found >= 3) + { + hasRecipe = true; + return; + } + } + hasRecipe = false; + } + + @Override + public int getSlotStackLimit(int slot) + { + return 1; + } + + @Override + public boolean isItemValid(int slot, ItemStack stack) + { + return Helpers.isItem(stack, FLTags.Items.USABLE_IN_STOVETOP_SOUP); + } + + public void handleCooking() + { + assert level != null; + if (isBoiling()) + { + if (boilingTicks < DURATION) + { + boilingTicks++; + if (boilingTicks == 1) markForSync(); + } + else + { + assembleSoup(); + boilingTicks = 0; + updateCachedRecipe(); + for (int i = 0; i < SLOTS; i++) + { + inventory.setStackInSlot(i, ItemStack.EMPTY); + inventory.getFluidHandler().drain(Integer.MAX_VALUE, IFluidHandler.FluidAction.EXECUTE); + } + markForSync(); + } + } + else if (boilingTicks > 0) + { + boilingTicks = 0; + markForSync(); + } + } + + public void assembleSoup() + { + int ingredientCount = 0; + float water = 20, saturation = 2; + float[] nutrition = new float[Nutrient.TOTAL]; + ItemStack soupStack = ItemStack.EMPTY; + for (int i = 0; i < SLOTS; i++) + { + ItemStack stack = inventory.getStackInSlot(i); + IFood food = stack.getCapability(FoodCapability.CAPABILITY).resolve().orElse(null); + if (food != null) + { + if (food.isRotten()) // this should mostly not happen since the ingredients are not rotten to start, but worth checking + { + ingredientCount = 0; + break; + } + final FoodData data = food.getData(); + water += data.water(); + saturation += data.saturation(); + for (Nutrient nutrient : Nutrient.VALUES) + { + nutrition[nutrient.ordinal()] += data.nutrient(nutrient); + } + ingredientCount++; + } + } + if (ingredientCount > 0) + { + float multiplier = 1 - (0.05f * ingredientCount); // per-serving multiplier of nutrition + water *= multiplier; saturation *= multiplier; + Nutrient maxNutrient = Nutrient.GRAIN; // determines what item you get. this is a default + float maxNutrientValue = 0; + for (Nutrient nutrient : Nutrient.VALUES) + { + final int idx = nutrient.ordinal(); + nutrition[idx] *= multiplier; + if (nutrition[idx] > maxNutrientValue) + { + maxNutrientValue = nutrition[idx]; + maxNutrient = nutrient; + } + } + FoodData data = FoodData.create(SoupPotRecipe.SOUP_HUNGER_VALUE, water, saturation, nutrition, SoupPotRecipe.SOUP_DECAY_MODIFIER); + int servings = (int) (ingredientCount / 2f) + 1; + long created = FoodCapability.getRoundedCreationDate(); + + soupStack = new ItemStack(TFCItems.SOUPS.get(maxNutrient).get(), servings); + soupStack.getCapability(FoodCapability.CAPABILITY) + .filter(food -> food instanceof DynamicBowlFood.DynamicBowlHandler) + .ifPresent(food -> { + DynamicBowlFood.DynamicBowlHandler handler = (DynamicBowlFood.DynamicBowlHandler) food; + handler.setCreationDate(created); + handler.setFood(data); + }); + } + + if (!soupStack.isEmpty()) + { + this.soupStack = soupStack; + } + } + + public InteractionResult interactWithOutput(Player player, ItemStack clickedWith) + { + if (Helpers.isItem(clickedWith.getItem(), TFCTags.Items.SOUP_BOWLS) && !soupStack.isEmpty()) + { + // set the internal bowl to the one we clicked with + soupStack.getCapability(FoodCapability.CAPABILITY) + .filter(food -> food instanceof DynamicBowlFood.DynamicBowlHandler) + .ifPresent(food -> ((DynamicBowlFood.DynamicBowlHandler) food).setBowl(clickedWith)); + + // take the player's bowl, give a soup + clickedWith.shrink(1); + ItemHandlerHelper.giveItemToPlayer(player, soupStack.split(1)); + markForSync(); + return InteractionResult.SUCCESS; + } + return InteractionResult.PASS; + } + + @Override + public void loadAdditional(CompoundTag nbt) + { + super.loadAdditional(nbt); + if (nbt.contains("soup")) + { + soupStack = ItemStack.of(nbt.getCompound("soup")); + } + } + + @Override + public void saveAdditional(CompoundTag nbt) + { + super.saveAdditional(nbt); + if (!soupStack.isEmpty()) + { + nbt.put("soup", soupStack.save(new CompoundTag())); + } + } + + @Override + public boolean isBoiling() + { + assert level != null; + if (level.isClientSide) + { + return boilingTicks > 0; + } + return hasRecipe && temperature > MIN_TEMP; + } + + public static class StovetopPotInventory extends BoilingInventory + { + public StovetopPotInventory(InventoryBlockEntity entity) + { + super(entity, SLOTS, new InventoryFluidTank(1000, fluid -> fluid.getFluid().isSame(Fluids.WATER), (StovetopPotBlockEntity) entity)); + } + } +} diff --git a/src/main/java/com/eerussianguy/firmalife/common/blockentities/VatBlockEntity.java b/src/main/java/com/eerussianguy/firmalife/common/blockentities/VatBlockEntity.java index 2afa2dcf..bfe0002b 100644 --- a/src/main/java/com/eerussianguy/firmalife/common/blockentities/VatBlockEntity.java +++ b/src/main/java/com/eerussianguy/firmalife/common/blockentities/VatBlockEntity.java @@ -9,170 +9,50 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; -import net.minecraft.sounds.SoundEvents; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.INBTSerializable; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fluids.capability.IFluidHandler; -import net.minecraftforge.fluids.capability.templates.FluidTank; -import net.minecraftforge.items.IItemHandlerModifiable; -import net.minecraftforge.items.ItemStackHandler; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import net.dries007.tfc.common.TFCTags; import net.dries007.tfc.common.blockentities.InventoryBlockEntity; -import net.dries007.tfc.common.blockentities.TickableInventoryBlockEntity; -import net.dries007.tfc.common.capabilities.Capabilities; -import net.dries007.tfc.common.capabilities.DelegateFluidHandler; -import net.dries007.tfc.common.capabilities.DelegateItemHandler; -import net.dries007.tfc.common.capabilities.FluidTankCallback; import net.dries007.tfc.common.capabilities.InventoryFluidTank; -import net.dries007.tfc.common.capabilities.InventoryItemHandler; -import net.dries007.tfc.common.capabilities.PartialFluidHandler; import net.dries007.tfc.common.capabilities.PartialItemHandler; -import net.dries007.tfc.common.capabilities.SidedHandler; -import net.dries007.tfc.common.capabilities.heat.HeatCapability; -import net.dries007.tfc.common.capabilities.heat.IHeatBlock; -import net.dries007.tfc.common.recipes.inventory.EmptyInventory; import net.dries007.tfc.util.Helpers; -import net.dries007.tfc.util.calendar.Calendars; -import net.dries007.tfc.util.calendar.ICalendarTickable; -public class VatBlockEntity extends TickableInventoryBlockEntity implements ICalendarTickable, FluidTankCallback +public class VatBlockEntity extends BoilingBlockEntity { public static void serverTick(Level level, BlockPos pos, BlockState state, VatBlockEntity vat) { vat.checkForLastTickSync(); vat.checkForCalendarUpdate(); - final List excess = vat.inventory.excess; - if (!excess.isEmpty() && vat.inventory.getStackInSlot(0).isEmpty()) - { - vat.inventory.setStackInSlot(0, excess.remove(0)); - } if (vat.needsRecipeUpdate) { vat.updateCachedRecipe(); } - if (vat.temperature != vat.targetTemperature) - { - vat.temperature = HeatCapability.adjustTempTowards(vat.temperature, vat.targetTemperature); - } - if (vat.targetTemperatureStabilityTicks > 0) - { - vat.targetTemperatureStabilityTicks--; - } - if (vat.targetTemperature > 0 && vat.targetTemperatureStabilityTicks == 0) + final List excess = vat.inventory.excess; + if (!excess.isEmpty() && vat.inventory.getStackInSlot(0).isEmpty()) { - // target temperature decays constantly, since it is set externally. As long as we don't consider ourselves 'stable' - vat.targetTemperature = HeatCapability.adjustTempTowards(vat.targetTemperature, 0); + vat.inventory.setStackInSlot(0, excess.remove(0)); } + vat.tickTemperature(); vat.handleCooking(); } public static final int CAPACITY = 10_000; - private int boilingTicks = 0; - private long lastUpdateTick; - private float temperature = 0; - private float targetTemperature = 0; - private int targetTemperatureStabilityTicks = 0; - private final SidedHandler.Builder sidedFluidInventory; - private boolean needsRecipeUpdate = true; @Nullable private VatRecipe cachedRecipe = null; - private final SidedHandler.Noop sidedHeat; - public VatBlockEntity(BlockPos pos, BlockState state) { super(FLBlockEntities.VAT.get(), pos, state, VatInventory::new, FLHelpers.blockEntityName("vat")); - lastUpdateTick = Calendars.SERVER.getTicks(); - - sidedFluidInventory = new SidedHandler.Builder<>(inventory); - sidedFluidInventory.on(new PartialFluidHandler(inventory).insert(), Direction.UP) - .on(new PartialFluidHandler(inventory).extract(), Direction.Plane.HORIZONTAL); sidedInventory.on(new PartialItemHandler(inventory).insert(), Direction.Plane.HORIZONTAL); - - sidedHeat = new SidedHandler.Noop<>(inventory); - } - - public float getTemperature() - { - return temperature; - } - - @Override - public void fluidTankChanged() - { - FluidTankCallback.super.fluidTankChanged(); - needsRecipeUpdate = true; - } - - @Override - public void setAndUpdateSlots(int slot) - { - super.setAndUpdateSlots(slot); - needsRecipeUpdate = true; - } - - @Override - public void onCalendarUpdate(long ticks) - { - assert level != null; - // Crucible has no fuel to consume, but it does drop the internal target and temperature over time. - final boolean wasHot = temperature > 0; - targetTemperature = HeatCapability.adjustTempTowards(targetTemperature, 0, ticks); - temperature = HeatCapability.adjustTempTowards(temperature, targetTemperature, ticks); - if (wasHot && temperature == 0) - { - boilingTicks = 0; - markForSync(); - } - } - - @Override - public long getLastUpdateTick() - { - return lastUpdateTick; - } - - @Override - public void setLastUpdateTick(long tick) - { - lastUpdateTick = tick; - } - - - @Override - public void loadAdditional(CompoundTag nbt) - { - lastUpdateTick = nbt.getLong("lastTick"); - temperature = nbt.getFloat("temperature"); - targetTemperature = nbt.getFloat("targetTemperature"); - targetTemperatureStabilityTicks = nbt.getInt("targetTemperatureStabilityTicks"); - boilingTicks = nbt.getInt("boilingTicks"); - needsRecipeUpdate = true; - super.loadAdditional(nbt); - } - - @Override - public void saveAdditional(CompoundTag nbt) - { - nbt.putLong("lastTick", lastUpdateTick); - nbt.putFloat("temperature", temperature); - nbt.putFloat("targetTemperature", targetTemperature); - nbt.putInt("targetTemperatureStabilityTicks", targetTemperatureStabilityTicks); - nbt.putInt("boilingTicks", boilingTicks); - super.saveAdditional(nbt); } - private void updateCachedRecipe() + public void updateCachedRecipe() { assert level != null; if (inventory.excess.isEmpty()) @@ -218,21 +98,7 @@ else if (boilingTicks > 0) } } - @NotNull @Override - public LazyOptional getCapability(Capability cap, @Nullable Direction side) - { - if (cap == HeatCapability.BLOCK_CAPABILITY) - { - return sidedHeat.getSidedHandler(side).cast(); - } - if (cap == Capabilities.FLUID) - { - return sidedFluidInventory.getSidedHandler(side).cast(); - } - return super.getCapability(cap, side); - } - public boolean isBoiling() { assert level != null; @@ -247,18 +113,13 @@ public boolean isBoiling() return cachedRecipe != null && temperature > cachedRecipe.getTemperature(); } - public static class VatInventory implements EmptyInventory, DelegateItemHandler, DelegateFluidHandler, INBTSerializable, CrucibleLikeHeatBlock, FluidTankCallback + public static class VatInventory extends BoilingInventory { - private final VatBlockEntity vat; - private final ItemStackHandler inventory; - private final FluidTank tank; private final List excess; - public VatInventory(InventoryBlockEntity entity) + public VatInventory(InventoryBlockEntity entity) { - this.vat = (VatBlockEntity) entity; - this.inventory = new InventoryItemHandler(entity, 1); - this.tank = new InventoryFluidTank(CAPACITY, fluid -> Helpers.isFluid(fluid.getFluid(), TFCTags.Fluids.USABLE_IN_POT), vat); + super(entity, 1, new InventoryFluidTank(CAPACITY, fluid -> Helpers.isFluid(fluid.getFluid(), TFCTags.Fluids.USABLE_IN_POT), (VatBlockEntity) entity)); this.excess = new ArrayList<>(); } @@ -271,31 +132,10 @@ public void insertItemWithOverflow(ItemStack stack) } } - @NotNull - @Override - public ItemStack extractItem(int slot, int amount, boolean simulate) - { - return vat.isBoiling() ? ItemStack.EMPTY : inventory.extractItem(slot, amount, simulate); - } - - @Override - public IFluidHandler getFluidHandler() - { - return tank; - } - - @Override - public IItemHandlerModifiable getItemHandler() - { - return inventory; - } - @Override public CompoundTag serializeNBT() { - CompoundTag nbt = new CompoundTag(); - nbt.put("inventory", inventory.serializeNBT()); - nbt.put("tank", tank.writeToNBT(new CompoundTag())); + CompoundTag nbt = super.serializeNBT(); FLHelpers.writeItemStackList(excess, nbt, "excess"); return nbt; } @@ -303,42 +143,8 @@ public CompoundTag serializeNBT() @Override public void deserializeNBT(CompoundTag nbt) { - inventory.deserializeNBT(nbt.getCompound("inventory")); - tank.readFromNBT(nbt.getCompound("tank")); + super.deserializeNBT(nbt); FLHelpers.readItemStackList(excess, nbt, "excess"); } - - @Override - public float getTemperature() - { - return vat.temperature; - } - - @Override - public void setTargetTemperature(float temp) - { - vat.targetTemperature = temp; - } - - @Override - public float getTargetTemperature() - { - return vat.targetTemperature; - } - - @Override - public void resetStability() - { - vat.targetTemperatureStabilityTicks = OvenTopBlockEntity.TARGET_TEMPERATURE_STABILITY_TICKS; - vat.markForSync(); - } - - @Override - public void setTemperature(float temperature) - { - CrucibleLikeHeatBlock.super.setTemperature(temperature); - vat.temperature = temperature; - } - } } diff --git a/src/main/java/com/eerussianguy/firmalife/common/blocks/CheeseWheelBlock.java b/src/main/java/com/eerussianguy/firmalife/common/blocks/CheeseWheelBlock.java index d19acf0d..d687a41b 100644 --- a/src/main/java/com/eerussianguy/firmalife/common/blocks/CheeseWheelBlock.java +++ b/src/main/java/com/eerussianguy/firmalife/common/blocks/CheeseWheelBlock.java @@ -3,6 +3,7 @@ import java.util.Random; import java.util.function.Supplier; +import com.eerussianguy.firmalife.common.blockentities.FLBlockEntities; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; @@ -31,7 +32,6 @@ import com.eerussianguy.firmalife.common.util.FoodAge; import com.eerussianguy.firmalife.config.FLConfig; import net.dries007.tfc.common.TFCTags; -import net.dries007.tfc.common.blockentities.TFCBlockEntities; import net.dries007.tfc.common.blocks.ExtendedProperties; import net.dries007.tfc.common.blocks.TFCBlockStateProperties; import net.dries007.tfc.common.blocks.devices.BottomSupportedDeviceBlock; @@ -73,11 +73,12 @@ public CheeseWheelBlock(ExtendedProperties properties, Supplier public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { ItemStack held = player.getItemInHand(hand); - if (Helpers.isItem(held, TFCTags.Items.KNIVES) && !player.isShiftKeyDown()) + if (Helpers.isItem(held, TFCTags.Items.KNIVES)) { final int count = state.getValue(COUNT); ItemStack drop = new ItemStack(slice.get()); FoodCapability.applyTrait(drop, state.getValue(AGE).getTrait()); + drop.getCapability(FoodCapability.CAPABILITY).ifPresent(cap -> cap.setCreationDate(FoodCapability.getRoundedCreationDate())); ItemHandlerHelper.giveItemToPlayer(player, drop); FLHelpers.resetCounter(level, pos); if (count - 1 == 0) @@ -86,6 +87,7 @@ public InteractionResult use(BlockState state, Level level, BlockPos pos, Player } else { + Helpers.playSound(level, pos, getSoundType(state, level, pos, player).getBreakSound()); level.setBlockAndUpdate(pos, state.setValue(COUNT, count - 1)); } } @@ -102,7 +104,7 @@ public boolean isRandomlyTicking(BlockState state) @SuppressWarnings("deprecation") public void randomTick(BlockState state, ServerLevel level, BlockPos pos, Random rand) { - level.getBlockEntity(pos, TFCBlockEntities.TICK_COUNTER.get()).ifPresent(counter -> { + level.getBlockEntity(pos, FLBlockEntities.TICK_COUNTER.get()).ifPresent(counter -> { if (state.getValue(AGING)) { long days = counter.getTicksSinceUpdate() / ICalendar.TICKS_IN_DAY; diff --git a/src/main/java/com/eerussianguy/firmalife/common/blocks/FLBlocks.java b/src/main/java/com/eerussianguy/firmalife/common/blocks/FLBlocks.java index 6320d01f..99921d8d 100644 --- a/src/main/java/com/eerussianguy/firmalife/common/blocks/FLBlocks.java +++ b/src/main/java/com/eerussianguy/firmalife/common/blocks/FLBlocks.java @@ -66,6 +66,8 @@ public class FLBlocks public static final RegistryObject OVEN_HOPPER = register("oven_hopper", () -> new OvenHopperBlock(ExtendedProperties.of(Material.STONE).strength(4.0f).sound(SoundType.STONE).blockEntity(FLBlockEntities.OVEN_HOPPER), FLBlocks.CURED_OVEN_HOPPER), DECORATIONS); public static final RegistryObject ASHTRAY = register("ashtray", () -> new AshtrayBlock(ExtendedProperties.of(Material.METAL).sound(SoundType.METAL).strength(2f).randomTicks().blockEntity(FLBlockEntities.ASHTRAY)), DECORATIONS); + public static final RegistryObject STOVETOP_GRILL = register("stovetop_grill", () -> new StovetopGrillBlock(ExtendedProperties.of(Material.METAL).sound(SoundType.METAL).strength(2f).blockEntity(FLBlockEntities.STOVETOP_GRILL).serverTicks(StovetopGrillBlockEntity::serverTick).noOcclusion())); + public static final RegistryObject STOVETOP_POT = register("stovetop_pot", () -> new StovetopPotBlock(ExtendedProperties.of(Material.METAL).sound(SoundType.METAL).strength(2f).blockEntity(FLBlockEntities.STOVETOP_POT).serverTicks(StovetopPotBlockEntity::serverTick).noOcclusion())); public static final RegistryObject DRYING_MAT = register("drying_mat", () -> new DryingMatBlock(ExtendedProperties.of(Material.DECORATION).strength(0.6f).sound(SoundType.AZALEA_LEAVES).flammable(60, 30).blockEntity(FLBlockEntities.DRYING_MAT).serverTicks(DryingMatBlockEntity::serverTick)), DECORATIONS); public static final RegistryObject SOLAR_DRIER = register("solar_drier", () -> new SolarDrierBlock(ExtendedProperties.of(Material.WOOD).strength(3.0f).sound(SoundType.WOOD).noOcclusion().flammable(60, 30).blockEntity(FLBlockEntities.SOLAR_DRIER).serverTicks(DryingMatBlockEntity::serverTick)), DECORATIONS); public static final RegistryObject BEEHIVE = register("beehive", () -> new FLBeehiveBlock(ExtendedProperties.of(Material.WOOD).strength(0.6f).sound(SoundType.WOOD).flammable(60, 30).randomTicks().blockEntity(FLBlockEntities.BEEHIVE).serverTicks(FLBeehiveBlockEntity::serverTick)), DECORATIONS); diff --git a/src/main/java/com/eerussianguy/firmalife/common/blocks/StovetopGrillBlock.java b/src/main/java/com/eerussianguy/firmalife/common/blocks/StovetopGrillBlock.java new file mode 100644 index 00000000..d0fec213 --- /dev/null +++ b/src/main/java/com/eerussianguy/firmalife/common/blocks/StovetopGrillBlock.java @@ -0,0 +1,76 @@ +package com.eerussianguy.firmalife.common.blocks; + +import java.util.Random; +import com.eerussianguy.firmalife.common.FLHelpers; +import com.eerussianguy.firmalife.common.blockentities.FLBlockEntities; +import com.eerussianguy.firmalife.common.blockentities.StovetopGrillBlockEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.VoxelShape; + +import net.dries007.tfc.common.TFCDamageSources; +import net.dries007.tfc.common.blocks.ExtendedProperties; +import net.dries007.tfc.common.blocks.devices.BottomSupportedDeviceBlock; +import net.dries007.tfc.util.Helpers; + +public class StovetopGrillBlock extends BottomSupportedDeviceBlock +{ + public static final VoxelShape SHAPE = box(1, 0, 1, 15, 1, 15); + + public StovetopGrillBlock(ExtendedProperties properties) + { + super(properties, InventoryRemoveBehavior.DROP, SHAPE); + } + + @Override + @SuppressWarnings("deprecation") + public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult result) + { + if (level.getBlockEntity(pos) instanceof StovetopGrillBlockEntity grill && player instanceof ServerPlayer serverPlayer) + { + Helpers.openScreen(serverPlayer, grill, pos); + } + return InteractionResult.SUCCESS; + } + + @Override + public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) + { + if (!entity.fireImmune() && entity instanceof LivingEntity && !EnchantmentHelper.hasFrostWalker((LivingEntity) entity) && level.getBlockEntity(pos) instanceof StovetopGrillBlockEntity grill && grill.getTemperature() > 0) + { + entity.hurt(TFCDamageSources.GRILL, 1.0F); + } + super.stepOn(level, pos, state, entity); + } + + @Override + public void animateTick(BlockState state, Level level, BlockPos pos, Random rand) + { + FLHelpers.readInventory(level, pos, FLBlockEntities.STOVETOP_GRILL, (grill, cap) -> { + for (int i = 0; i < StovetopGrillBlockEntity.SLOTS; i++) + { + if (!cap.getStackInSlot(i).isEmpty()) + { + double x = pos.getX() + 0.5D; + double y = pos.getY() + (1f / 16); + double z = pos.getZ() + 0.5D; + level.playLocalSound(x, y, z, SoundEvents.FURNACE_FIRE_CRACKLE, SoundSource.BLOCKS, 0.25F, rand.nextFloat() * 0.7F + 0.4F, false); + level.addParticle(ParticleTypes.SMOKE, x + rand.nextFloat() / 2 - 0.25, y, z + rand.nextFloat() / 2 - 0.25, 0.0D, 0.1D, 0.0D); + break; + } + } + }); + } +} diff --git a/src/main/java/com/eerussianguy/firmalife/common/blocks/StovetopPotBlock.java b/src/main/java/com/eerussianguy/firmalife/common/blocks/StovetopPotBlock.java new file mode 100644 index 00000000..f17dac7f --- /dev/null +++ b/src/main/java/com/eerussianguy/firmalife/common/blocks/StovetopPotBlock.java @@ -0,0 +1,81 @@ +package com.eerussianguy.firmalife.common.blocks; + +import java.util.Random; +import com.eerussianguy.firmalife.common.blockentities.StovetopPotBlockEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.VoxelShape; + +import net.dries007.tfc.client.particle.TFCParticles; +import net.dries007.tfc.common.blocks.ExtendedProperties; +import net.dries007.tfc.common.blocks.devices.BottomSupportedDeviceBlock; +import net.dries007.tfc.common.fluids.FluidHelpers; +import net.dries007.tfc.util.Helpers; + +public class StovetopPotBlock extends BottomSupportedDeviceBlock +{ + public static final VoxelShape SHAPE = box(3, 0, 3, 13, 6, 13); + + public StovetopPotBlock(ExtendedProperties properties) + { + super(properties, InventoryRemoveBehavior.DROP, SHAPE); + } + + @Override + public void animateTick(BlockState state, Level level, BlockPos pos, Random rand) + { + if (level.getBlockEntity(pos) instanceof StovetopPotBlockEntity pot) + { + if (!pot.isBoiling()) return; + double x = pos.getX() + 0.5; + double y = pos.getY() + (3f / 16); + double z = pos.getZ() + 0.5; + for (int i = 0; i < rand.nextInt(5) + 4; i++) + { + level.addParticle(TFCParticles.BUBBLE.get(), false, x + rand.nextFloat() * 0.375 - 0.1875, y, z + rand.nextFloat() * 0.375 - 0.1875, 0, 0.05D, 0); + } + level.addParticle(TFCParticles.STEAM.get(), false, x, y + 0.8, z, Helpers.triangle(rand), 0.5, Helpers.triangle(rand)); + level.playLocalSound(x, y, z, SoundEvents.WATER_AMBIENT, SoundSource.BLOCKS, 1.0F, rand.nextFloat() * 0.7F + 0.4F, false); + } + } + + @Override + @SuppressWarnings("deprecation") + public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult result) + { + if (level.getBlockEntity(pos) instanceof StovetopPotBlockEntity pot) + { + final ItemStack stack = player.getItemInHand(hand); + if (!pot.isBoiling() && FluidHelpers.transferBetweenBlockEntityAndItem(stack, pot, player, hand)) + { + pot.markForSync(); + } + else + { + if (!pot.isBoiling()) + { + final InteractionResult interactResult = pot.interactWithOutput(player, stack); + if (interactResult != InteractionResult.PASS) + { + return interactResult; + } + } + if (player instanceof ServerPlayer serverPlayer) + { + Helpers.openScreen(serverPlayer, pot, pos); + } + } + return InteractionResult.sidedSuccess(level.isClientSide); + } + return InteractionResult.PASS; + } +} diff --git a/src/main/java/com/eerussianguy/firmalife/common/container/BeehiveContainer.java b/src/main/java/com/eerussianguy/firmalife/common/container/BeehiveContainer.java index 3f3a41ec..0c0f0f05 100644 --- a/src/main/java/com/eerussianguy/firmalife/common/container/BeehiveContainer.java +++ b/src/main/java/com/eerussianguy/firmalife/common/container/BeehiveContainer.java @@ -1,14 +1,10 @@ package com.eerussianguy.firmalife.common.container; import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.item.ItemStack; import com.eerussianguy.firmalife.common.blockentities.FLBeehiveBlockEntity; -import net.dries007.tfc.common.capabilities.Capabilities; -import net.dries007.tfc.common.container.BlockEntityContainer; -import net.dries007.tfc.common.container.CallbackSlot; -public class BeehiveContainer extends BlockEntityContainer +public class BeehiveContainer extends FourContainer { public static BeehiveContainer create(FLBeehiveBlockEntity hive, Inventory playerInventory, int windowId) { @@ -20,24 +16,4 @@ public BeehiveContainer(FLBeehiveBlockEntity blockEntity, Inventory playerInv, i super(FLContainerTypes.BEEHIVE.get(), windowId, blockEntity); } - @Override - protected boolean moveStack(ItemStack stack, int slotIndex) - { - return switch (typeOf(slotIndex)) - { - case MAIN_INVENTORY, HOTBAR -> !moveItemStackTo(stack, 0, FLBeehiveBlockEntity.SLOTS, false); - case CONTAINER -> !moveItemStackTo(stack, containerSlots, slots.size(), false); - }; - } - - @Override - protected void addContainerSlots() - { - blockEntity.getCapability(Capabilities.ITEM).ifPresent(handler -> { - addSlot(new CallbackSlot(blockEntity, handler, 0, 71, 23)); - addSlot(new CallbackSlot(blockEntity, handler, 1, 89, 23)); - addSlot(new CallbackSlot(blockEntity, handler, 2, 71, 41)); - addSlot(new CallbackSlot(blockEntity, handler, 3, 89, 41)); - }); - } } diff --git a/src/main/java/com/eerussianguy/firmalife/common/container/FLContainerTypes.java b/src/main/java/com/eerussianguy/firmalife/common/container/FLContainerTypes.java index 31dce86d..af3c7745 100644 --- a/src/main/java/com/eerussianguy/firmalife/common/container/FLContainerTypes.java +++ b/src/main/java/com/eerussianguy/firmalife/common/container/FLContainerTypes.java @@ -2,6 +2,8 @@ import java.util.function.Supplier; +import com.eerussianguy.firmalife.common.blockentities.StovetopGrillBlockEntity; +import com.eerussianguy.firmalife.common.blockentities.StovetopPotBlockEntity; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.inventory.MenuType; @@ -28,6 +30,8 @@ public class FLContainerTypes public static final DeferredRegister> CONTAINERS = DeferredRegister.create(ForgeRegistries.CONTAINERS, MOD_ID); public static final RegistryObject> BEEHIVE = FLContainerTypes.registerBlock("beehive", FLBlockEntities.BEEHIVE, BeehiveContainer::create); + public static final RegistryObject> STOVETOP_GRILL = FLContainerTypes.registerBlock("stovetop_grill", FLBlockEntities.STOVETOP_GRILL, StovetopGrillContainer::create); + public static final RegistryObject> STOVETOP_POT = FLContainerTypes.registerBlock("stovetop_pot", FLBlockEntities.STOVETOP_POT, StovetopPotContainer::create); public static final RegistryObject> PUMPKIN = FLContainerTypes.registerItem("pumpkin", FLContainerTypes::createPumpkin); public static KnappingContainer createPumpkin(ItemStack stack, InteractionHand hand, Inventory playerInventory, int windowId) diff --git a/src/main/java/com/eerussianguy/firmalife/common/container/FourContainer.java b/src/main/java/com/eerussianguy/firmalife/common/container/FourContainer.java new file mode 100644 index 00000000..f53a200e --- /dev/null +++ b/src/main/java/com/eerussianguy/firmalife/common/container/FourContainer.java @@ -0,0 +1,39 @@ +package com.eerussianguy.firmalife.common.container; + +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.ItemStack; + +import net.dries007.tfc.common.blockentities.InventoryBlockEntity; +import net.dries007.tfc.common.capabilities.Capabilities; +import net.dries007.tfc.common.container.BlockEntityContainer; +import net.dries007.tfc.common.container.CallbackSlot; + +public class FourContainer> extends BlockEntityContainer +{ + public FourContainer(MenuType containerType, int windowId, T blockEntity) + { + super(containerType, windowId, blockEntity); + } + + + @Override + protected boolean moveStack(ItemStack stack, int slotIndex) + { + return switch (typeOf(slotIndex)) + { + case MAIN_INVENTORY, HOTBAR -> !moveItemStackTo(stack, 0, 4, false); + case CONTAINER -> !moveItemStackTo(stack, containerSlots, slots.size(), false); + }; + } + + @Override + protected void addContainerSlots() + { + blockEntity.getCapability(Capabilities.ITEM).ifPresent(handler -> { + addSlot(new CallbackSlot(blockEntity, handler, 0, 71, 23)); + addSlot(new CallbackSlot(blockEntity, handler, 1, 89, 23)); + addSlot(new CallbackSlot(blockEntity, handler, 2, 71, 41)); + addSlot(new CallbackSlot(blockEntity, handler, 3, 89, 41)); + }); + } +} diff --git a/src/main/java/com/eerussianguy/firmalife/common/container/StovetopGrillContainer.java b/src/main/java/com/eerussianguy/firmalife/common/container/StovetopGrillContainer.java new file mode 100644 index 00000000..91a55a26 --- /dev/null +++ b/src/main/java/com/eerussianguy/firmalife/common/container/StovetopGrillContainer.java @@ -0,0 +1,19 @@ +package com.eerussianguy.firmalife.common.container; + +import com.eerussianguy.firmalife.common.blockentities.StovetopGrillBlockEntity; +import net.minecraft.world.entity.player.Inventory; + + +public class StovetopGrillContainer extends FourContainer +{ + public static StovetopGrillContainer create(StovetopGrillBlockEntity hive, Inventory playerInventory, int windowId) + { + return new StovetopGrillContainer(hive, playerInventory, windowId).init(playerInventory); + } + + public StovetopGrillContainer(StovetopGrillBlockEntity blockEntity, Inventory playerInv, int windowId) + { + super(FLContainerTypes.STOVETOP_GRILL.get(), windowId, blockEntity); + } + +} diff --git a/src/main/java/com/eerussianguy/firmalife/common/container/StovetopPotContainer.java b/src/main/java/com/eerussianguy/firmalife/common/container/StovetopPotContainer.java new file mode 100644 index 00000000..4e26a4c1 --- /dev/null +++ b/src/main/java/com/eerussianguy/firmalife/common/container/StovetopPotContainer.java @@ -0,0 +1,17 @@ +package com.eerussianguy.firmalife.common.container; + +import com.eerussianguy.firmalife.common.blockentities.StovetopPotBlockEntity; +import net.minecraft.world.entity.player.Inventory; + +public class StovetopPotContainer extends FourContainer +{ + public static StovetopPotContainer create(StovetopPotBlockEntity hive, Inventory playerInventory, int windowId) + { + return new StovetopPotContainer(hive, playerInventory, windowId).init(playerInventory); + } + + public StovetopPotContainer(StovetopPotBlockEntity blockEntity, Inventory playerInv, int windowId) + { + super(FLContainerTypes.STOVETOP_POT.get(), windowId, blockEntity); + } +} diff --git a/src/main/java/com/eerussianguy/firmalife/common/misc/FLInteractionManager.java b/src/main/java/com/eerussianguy/firmalife/common/misc/FLInteractionManager.java index 173fb8a5..20d85fae 100644 --- a/src/main/java/com/eerussianguy/firmalife/common/misc/FLInteractionManager.java +++ b/src/main/java/com/eerussianguy/firmalife/common/misc/FLInteractionManager.java @@ -1,12 +1,17 @@ package com.eerussianguy.firmalife.common.misc; +import com.eerussianguy.firmalife.common.blocks.OvenBottomBlock; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.InteractionResult; import net.minecraft.world.item.crafting.Ingredient; import com.eerussianguy.firmalife.common.FLTags; import com.eerussianguy.firmalife.common.blocks.FLBlocks; import com.eerussianguy.firmalife.common.container.FLContainerProviders; +import net.minecraft.world.level.Level; + import net.dries007.tfc.common.TFCTags; -import net.dries007.tfc.common.container.TFCContainerProviders; import net.dries007.tfc.common.items.TFCItems; import net.dries007.tfc.util.BlockItemPlacement; import net.dries007.tfc.util.InteractionManager; @@ -18,5 +23,35 @@ public static void init() InteractionManager.register(new BlockItemPlacement(TFCItems.WOOL_YARN, FLBlocks.WOOL_STRING)); InteractionManager.register(Ingredient.of(FLTags.Items.PUMPKIN_KNAPPING), false, true, InteractionManager.createKnappingInteraction((s, p) -> p.getInventory().contains(TFCTags.Items.KNIVES), FLContainerProviders.PUMPKIN_KNAPPING)); + + InteractionManager.register(Ingredient.of(TFCItems.WROUGHT_IRON_GRILL.get()), false, (stack, context) -> { + final Level level = context.getLevel(); + final BlockPos pos = context.getClickedPos(); + final BlockPos abovePos = pos.above(); + + if (context.getClickedFace() == Direction.UP && level.getBlockState(pos).getBlock() instanceof OvenBottomBlock && level.getBlockState(abovePos).isAir()) + { + level.setBlockAndUpdate(abovePos, FLBlocks.STOVETOP_GRILL.get().defaultBlockState()); + if (context.getPlayer() == null || !context.getPlayer().isCreative()) stack.shrink(1); + return InteractionResult.SUCCESS; + } + + return InteractionResult.PASS; + }); + + InteractionManager.register(Ingredient.of(TFCItems.POT.get()), false, (stack, context) -> { + final Level level = context.getLevel(); + final BlockPos pos = context.getClickedPos(); + final BlockPos abovePos = pos.above(); + + if (context.getClickedFace() == Direction.UP && level.getBlockState(pos).getBlock() instanceof OvenBottomBlock && level.getBlockState(abovePos).isAir()) + { + level.setBlockAndUpdate(abovePos, FLBlocks.STOVETOP_POT.get().defaultBlockState()); + if (context.getPlayer() == null || !context.getPlayer().isCreative()) stack.shrink(1); + return InteractionResult.SUCCESS; + } + + return InteractionResult.PASS; + }); } } diff --git a/src/main/resources/assets/firmalife/blockstates/stovetop_grill.json b/src/main/resources/assets/firmalife/blockstates/stovetop_grill.json new file mode 100644 index 00000000..8c077f24 --- /dev/null +++ b/src/main/resources/assets/firmalife/blockstates/stovetop_grill.json @@ -0,0 +1,8 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "variants": { + "": { + "model": "firmalife:block/stovetop_grill" + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/firmalife/blockstates/stovetop_pot.json b/src/main/resources/assets/firmalife/blockstates/stovetop_pot.json new file mode 100644 index 00000000..742bbc17 --- /dev/null +++ b/src/main/resources/assets/firmalife/blockstates/stovetop_pot.json @@ -0,0 +1,8 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "variants": { + "": { + "model": "firmalife:block/stovetop_pot" + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/firmalife/lang/en_us.json b/src/main/resources/assets/firmalife/lang/en_us.json index ac45b1d7..dc985543 100644 --- a/src/main/resources/assets/firmalife/lang/en_us.json +++ b/src/main/resources/assets/firmalife/lang/en_us.json @@ -62,6 +62,8 @@ "block.firmalife.wool_string": "Wool String", "block.firmalife.climate_station": "Climate Station", "block.firmalife.squirting_moisture_transducer": "Squirting Moisture Transducer", + "block.firmalife.stovetop_grill": "Stovetop Grill", + "block.firmalife.stovetop_pot": "Stovetop Pot", "block.firmalife.sprinkler": "Sprinkler", "block.firmalife.dribbler": "Dribbler", "block.firmalife.beehive": "Wooden Beehive", @@ -430,6 +432,8 @@ "firmalife.block_entity.vat": "Vat", "firmalife.block_entity.oven_hopper": "Oven Hopper", "firmalife.block_entity.ashtray": "Ashtray", + "firmalife.block_entity.stovetop_grill": "Stovetop Grill", + "firmalife.block_entity.stovetop_pot": "Stovetop Pot", "block.firmalife.fluid.yeast_starter": "Yeast Starter", "item.firmalife.bucket.yeast_starter": "Yeast Starter Bucket", "fluid.firmalife.yeast_starter": "Yeast Starter", diff --git a/src/main/resources/assets/firmalife/models/block/stovetop_grill.json b/src/main/resources/assets/firmalife/models/block/stovetop_grill.json new file mode 100644 index 00000000..edda8a91 --- /dev/null +++ b/src/main/resources/assets/firmalife/models/block/stovetop_grill.json @@ -0,0 +1,21 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "0": "tfc:item/wrought_iron_grill", + "particle": "tfc:item/wrought_iron_grill" + }, + "elements": [ + { + "from": [1, 0, 1], + "to": [15, 1, 15], + "faces": { + "north": {"uv": [1, 1, 15, 2], "texture": "#0"}, + "east": {"uv": [1, 1, 15, 2], "texture": "#0"}, + "south": {"uv": [1, 1, 15, 2], "texture": "#0"}, + "west": {"uv": [1, 1, 15, 2], "texture": "#0"}, + "up": {"uv": [1, 1, 15, 15], "texture": "#0"}, + "down": {"uv": [1, 1, 15, 15], "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/firmalife/models/block/stovetop_pot.json b/src/main/resources/assets/firmalife/models/block/stovetop_pot.json new file mode 100644 index 00000000..b3186d80 --- /dev/null +++ b/src/main/resources/assets/firmalife/models/block/stovetop_pot.json @@ -0,0 +1,176 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "particle": "tfc:block/ceramic/large_vessel/side", + "pot_side": "tfc:block/ceramic/large_vessel/side", + "pot_bottom": "tfc:block/ceramic/large_vessel/bottom" + }, + "elements": [ + { + "name": "PotNorth", + "from": [4, 1, 3], + "to": [12, 4, 4], + "faces": { + "north": {"uv": [6, 4, 15, 8], "texture": "#pot_side"}, + "east": {"uv": [5, 7, 13, 11], "texture": "#pot_side"}, + "south": {"uv": [8, 8, 16, 12], "texture": "#pot_side"}, + "west": {"uv": [0, 0, 1, 4], "texture": "#pot_side"}, + "up": {"uv": [0, 0, 8, 1], "texture": "#pot_side"}, + "down": {"uv": [0, 0, 8, 1], "texture": "#pot_side"} + } + }, + { + "name": "PotNorthRim", + "from": [5, 4, 4], + "to": [12, 5, 5], + "faces": { + "north": {"uv": [0, 0, 7, 1], "texture": "#pot_side"}, + "east": {"uv": [0, 0, 1, 1], "texture": "#pot_side"}, + "south": {"uv": [0, 0, 8, 1], "texture": "#pot_side"}, + "up": {"uv": [0, 0, 1, 8], "rotation": 270, "texture": "#pot_side"}, + "down": {"uv": [0, 0, 1, 8], "rotation": 90, "texture": "#pot_side"} + } + }, + { + "name": "PotNorthRim2", + "from": [4, 5, 3], + "to": [12, 6, 4], + "faces": { + "north": {"uv": [0, 0, 7, 1], "texture": "#pot_side"}, + "east": {"uv": [0, 0, 1, 1], "texture": "#pot_side"}, + "south": {"uv": [0, 0, 7, 1], "texture": "#pot_side"}, + "west": {"uv": [0, 0, 1, 1], "texture": "#pot_side"}, + "up": {"uv": [0, 0, 1, 7], "rotation": 270, "texture": "#pot_side"}, + "down": {"uv": [0, 0, 1, 8], "rotation": 90, "texture": "#pot_side"} + } + }, + { + "name": "PotEast", + "from": [12, 1, 4], + "to": [13, 4, 12], + "faces": { + "north": {"uv": [0, 0, 1, 4], "texture": "#pot_side"}, + "east": {"uv": [6, 4, 15, 8], "texture": "#pot_side"}, + "south": {"uv": [0, 0, 1, 4], "texture": "#pot_side"}, + "west": {"uv": [8, 8, 16, 12], "texture": "#pot_side"}, + "up": {"uv": [0, 0, 1, 8], "texture": "#pot_side"}, + "down": {"uv": [0, 0, 1, 8], "texture": "#pot_side"} + } + }, + { + "name": "PotEastRim", + "from": [11, 4, 5], + "to": [12, 5, 12], + "faces": { + "east": {"uv": [0, 0, 9, 1], "texture": "#pot_side"}, + "south": {"uv": [0, 0, 1, 1], "texture": "#pot_side"}, + "west": {"uv": [0, 0, 8, 1], "texture": "#pot_side"}, + "up": {"uv": [0, 0, 1, 8], "texture": "#pot_side"}, + "down": {"uv": [0, 0, 1, 8], "texture": "#pot_side"} + } + }, + { + "name": "PotEastRim2", + "from": [12, 5, 4], + "to": [13, 6, 12], + "faces": { + "north": {"uv": [0, 0, 1, 1], "texture": "#pot_side"}, + "east": {"uv": [0, 0, 7, 1], "texture": "#pot_side"}, + "south": {"uv": [0, 0, 1, 1], "texture": "#pot_side"}, + "west": {"uv": [0, 0, 7, 1], "texture": "#pot_side"}, + "up": {"uv": [0, 0, 1, 7], "texture": "#pot_side"}, + "down": {"uv": [0, 0, 1, 8], "texture": "#pot_side"} + } + }, + { + "name": "PotSouth", + "from": [4, 1, 12], + "to": [12, 4, 13], + "faces": { + "north": {"uv": [8, 8, 16, 12], "texture": "#pot_side"}, + "east": {"uv": [0, 0, 1, 4], "texture": "#pot_side"}, + "south": {"uv": [0, 0, 8, 4], "texture": "#pot_side"}, + "west": {"uv": [0, 0, 1, 4], "texture": "#pot_side"}, + "up": {"uv": [0, 0, 8, 1], "texture": "#pot_side"}, + "down": {"uv": [0, 0, 8, 1], "texture": "#pot_side"} + } + }, + { + "name": "PotSouthRim", + "from": [4, 4, 11], + "to": [11, 5, 12], + "faces": { + "north": {"uv": [0, 0, 9, 1], "texture": "#pot_side"}, + "south": {"uv": [0, 0, 8, 1], "texture": "#pot_side"}, + "west": {"uv": [0, 0, 1, 1], "texture": "#pot_side"}, + "up": {"uv": [0, 0, 1, 8], "rotation": 270, "texture": "#pot_side"}, + "down": {"uv": [0, 0, 1, 8], "rotation": 90, "texture": "#pot_side"} + } + }, + { + "name": "PotSouthRim2", + "from": [4, 5, 12], + "to": [12, 6, 13], + "faces": { + "north": {"uv": [0, 0, 7, 1], "texture": "#pot_side"}, + "east": {"uv": [0, 0, 1, 1], "texture": "#pot_side"}, + "south": {"uv": [0, 0, 7, 1], "texture": "#pot_side"}, + "west": {"uv": [0, 0, 1, 1], "texture": "#pot_side"}, + "up": {"uv": [0, 0, 1, 7], "rotation": 270, "texture": "#pot_side"}, + "down": {"uv": [0, 0, 1, 8], "rotation": 90, "texture": "#pot_side"} + } + }, + { + "name": "PotWest", + "from": [3, 1, 4], + "to": [4, 4, 12], + "faces": { + "north": {"uv": [0, 0, 1, 4], "texture": "#pot_side"}, + "east": {"uv": [8, 8, 16, 12], "texture": "#pot_side"}, + "south": {"uv": [0, 0, 1, 4], "texture": "#pot_side"}, + "west": {"uv": [7, 4, 15, 8], "texture": "#pot_side"}, + "up": {"uv": [0, 0, 1, 8], "texture": "#pot_side"}, + "down": {"uv": [0, 0, 1, 8], "texture": "#pot_side"} + } + }, + { + "name": "PotWestRim", + "from": [4, 4, 4], + "to": [5, 5, 11], + "faces": { + "north": {"uv": [0, 0, 1, 1], "texture": "#pot_side"}, + "east": {"uv": [0, 0, 7, 1], "texture": "#pot_side"}, + "west": {"uv": [0, 0, 7, 1], "texture": "#pot_side"}, + "up": {"uv": [0, 0, 1, 7], "texture": "#pot_side"}, + "down": {"uv": [0, 0, 1, 8], "texture": "#pot_side"} + } + }, + { + "name": "PotWestRim2", + "from": [3, 5, 4], + "to": [4, 6, 12], + "faces": { + "north": {"uv": [0, 0, 1, 1], "texture": "#pot_side"}, + "east": {"uv": [0, 0, 7, 1], "texture": "#pot_side"}, + "south": {"uv": [0, 0, 1, 1], "texture": "#pot_side"}, + "west": {"uv": [0, 0, 7, 1], "texture": "#pot_side"}, + "up": {"uv": [0, 0, 1, 7], "texture": "#pot_side"}, + "down": {"uv": [0, 0, 1, 8], "texture": "#pot_side"} + } + }, + { + "name": "PotBottom", + "from": [4, 0, 4], + "to": [12, 2, 12], + "faces": { + "north": {"uv": [8, 12, 16, 14], "texture": "#pot_side"}, + "east": {"uv": [8, 12, 16, 14], "texture": "#pot_side"}, + "south": {"uv": [8, 12, 16, 14], "texture": "#pot_side"}, + "west": {"uv": [8, 12, 16, 14], "texture": "#pot_side"}, + "up": {"uv": [3, 4, 11, 12], "texture": "#pot_bottom"}, + "down": {"uv": [0, 0, 8, 8], "texture": "#pot_bottom"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/data/firmalife/loot_tables/blocks/stovetop_grill.json b/src/main/resources/data/firmalife/loot_tables/blocks/stovetop_grill.json new file mode 100644 index 00000000..89fa7e81 --- /dev/null +++ b/src/main/resources/data/firmalife/loot_tables/blocks/stovetop_grill.json @@ -0,0 +1,21 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "type": "minecraft:block", + "pools": [ + { + "name": "loot_pool", + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "tfc:wrought_iron_grill" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/data/firmalife/loot_tables/blocks/stovetop_pot.json b/src/main/resources/data/firmalife/loot_tables/blocks/stovetop_pot.json new file mode 100644 index 00000000..66aad5b9 --- /dev/null +++ b/src/main/resources/data/firmalife/loot_tables/blocks/stovetop_pot.json @@ -0,0 +1,21 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "type": "minecraft:block", + "pools": [ + { + "name": "loot_pool", + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "tfc:ceramic/pot" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/beekeeping.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/beekeeping.json index 6c60f249..d82b1f4e 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/beekeeping.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/beekeeping.json @@ -55,5 +55,5 @@ } ], "read_by_default": true, - "sortnum": 8 + "sortnum": 9 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/berry_bushes.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/berry_bushes.json index 75b04b9a..6502b4ac 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/berry_bushes.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/berry_bushes.json @@ -37,5 +37,5 @@ } ], "read_by_default": true, - "sortnum": 19 + "sortnum": 21 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/bread.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/bread.json index da6d7150..14b4b6ae 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/bread.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/bread.json @@ -15,5 +15,5 @@ } ], "read_by_default": true, - "sortnum": 14 + "sortnum": 16 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/cellar.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/cellar.json index abeeb529..f40804c1 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/cellar.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/cellar.json @@ -30,5 +30,5 @@ } ], "read_by_default": true, - "sortnum": 2 + "sortnum": 3 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/cheese.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/cheese.json index f96b4e33..bf05fa74 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/cheese.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/cheese.json @@ -83,5 +83,5 @@ } ], "read_by_default": true, - "sortnum": 0 + "sortnum": 1 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/chocolate.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/chocolate.json index 91da1277..9e13deb1 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/chocolate.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/chocolate.json @@ -23,5 +23,5 @@ } ], "read_by_default": true, - "sortnum": 20 + "sortnum": 22 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/climate_station.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/climate_station.json index f40bc358..865c5706 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/climate_station.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/climate_station.json @@ -52,5 +52,5 @@ } ], "read_by_default": true, - "sortnum": 1 + "sortnum": 2 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/differences_from_tfc.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/differences_from_tfc.json new file mode 100644 index 00000000..060dc0d1 --- /dev/null +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/differences_from_tfc.json @@ -0,0 +1,29 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "name": "Differences from TFC (Read first!)", + "category": "firmalife:firmalife", + "icon": "tfc:food/wheat_bread", + "pages": [ + { + "type": "patchouli:text", + "text": "Firmalife makes a few changes to how things operate in regular TFC. This chapter exists to help direct you towards areas where this is very different." + }, + { + "type": "patchouli:text", + "text": "$(l:firmalife:firmalife/cheese)Cheese$() is made through a more complex process. It can be placed in world, and has the option of aging in a $(l:firmalife:firmalife/cellar)Cellar$().", + "title": "Cheese Aging" + }, + { + "type": "patchouli:text", + "text": "$(l:firmalife:firmalife/bread)Bread$() is made through a more complex process, requiring yeast and sweetener. Regular TFC bread makes flatbread, which is worse nutritionally.", + "title": "Cheese Aging" + }, + { + "type": "patchouli:text", + "text": "Firmalife has a greater emphasis on sugar. While it can still be obtained through sugar cane, consider using honey (from bees) or making sugar from beets!", + "title": "Sweeteners" + } + ], + "read_by_default": true, + "sortnum": 0 +} \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/drying.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/drying.json index fbc6aff6..55d42c05 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/drying.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/drying.json @@ -39,5 +39,5 @@ } ], "read_by_default": true, - "sortnum": 11 + "sortnum": 12 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/food_shelves.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/food_shelves.json index a47279b1..b4a37c96 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/food_shelves.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/food_shelves.json @@ -15,5 +15,5 @@ } ], "read_by_default": true, - "sortnum": 3 + "sortnum": 4 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/fruit_trees.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/fruit_trees.json index 98b4a0c9..1313a3a7 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/fruit_trees.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/fruit_trees.json @@ -174,5 +174,5 @@ } ], "read_by_default": true, - "sortnum": 18 + "sortnum": 20 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/greenhouse.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/greenhouse.json index 16fd0f59..679f02ff 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/greenhouse.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/greenhouse.json @@ -51,5 +51,5 @@ } ], "read_by_default": true, - "sortnum": 5 + "sortnum": 6 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/hangers.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/hangers.json index 0ada09cc..cd8d4f6e 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/hangers.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/hangers.json @@ -15,5 +15,5 @@ } ], "read_by_default": true, - "sortnum": 4 + "sortnum": 5 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/herbs_and_spices.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/herbs_and_spices.json index 2419b4d2..346d48a3 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/herbs_and_spices.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/herbs_and_spices.json @@ -62,5 +62,5 @@ } ], "read_by_default": true, - "sortnum": 17 + "sortnum": 19 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/jar.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/jar.json index 8f8bccbe..5615265f 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/jar.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/jar.json @@ -82,5 +82,5 @@ } ], "read_by_default": true, - "sortnum": 9 + "sortnum": 10 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/mixing_bowl.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/mixing_bowl.json index 91e1f246..34b40a3d 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/mixing_bowl.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/mixing_bowl.json @@ -15,5 +15,5 @@ } ], "read_by_default": true, - "sortnum": 16 + "sortnum": 18 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/more_fertilizer.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/more_fertilizer.json index 9aa04aa2..1caa7a0d 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/more_fertilizer.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/more_fertilizer.json @@ -143,5 +143,5 @@ } ], "read_by_default": true, - "sortnum": 15 + "sortnum": 17 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/oven_appliances.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/oven_appliances.json new file mode 100644 index 00000000..60c173a3 --- /dev/null +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/oven_appliances.json @@ -0,0 +1,64 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "name": "Oven Appliances", + "category": "firmalife:firmalife", + "icon": "tfc:vat", + "pages": [ + { + "type": "patchouli:text", + "text": "$(l:firmalife:firmalife/ovens)Ovens$() have a number of devices that interact with them, that extend their functionality. This is because ovens are modular in nature." + }, + { + "type": "patchouli:crafting", + "recipe": "firmalife:crafting/oven_hopper", + "text": "The $(thing)Oven Hopper$() will input logs into any Bottom Oven that it is facing. It holds 16 logs (4 stacks of 4, like a log pile), and its inventory is fed by dropping items in the top. It can also be fed via automation from other mods." + }, + { + "type": "patchouli:crafting", + "recipe": "firmalife:crafting/ashtray", + "text": "The $(thing)Ashtray$() collects $(thing)Wood Ash$() when placed below a $(thing)Bottom Oven Block$(). There is a 0.5 chance it gains ash when fuel is consumed. Ash is extracted with $(item)$(k:key.use)$() and inserted via attacking it." + }, + { + "type": "patchouli:crafting", + "recipe": "firmalife:crafting/vat", + "text": "The $(thing)Vat$() produces some select boiling recipes in bulk. It has one slot for items, and 10,000mB of fluid space, similar to a barrel." + }, + { + "type": "patchouli:text", + "text": "For example, the vat can be used to make $(thing)Olive Oil Water$() using a ratio of 1 Olive Paste to 200 mB Water. To use a vat, $(item)$(k:key.use)$() it with fluids and items to add them to the inventory. With an empty hand and $(item)$(k:key.sneak)$() held, click to seal and unseal the vat. A vat will not boil until it is sealed." + }, + { + "type": "patchouli:text", + "text": "Vats should be placed on the block above a $(thing)Bottom Oven$(). If the vat would overflow on completion of the recipe, it will not boil, so be sure not to overfill it -- especially with recipes that produce more fluid than they consume!" + }, + { + "type": "patchouli:multiblock", + "multiblock": { + "pattern": [ + [ + "X" + ], + [ + "Y" + ], + [ + "0" + ] + ], + "mapping": { + "X": "firmalife:vat", + "Y": "firmalife:cured_oven_bottom" + } + }, + "name": "", + "text": "", + "enable_visualize": false + }, + { + "type": "patchouli:text", + "text": "Pots and Grills from TFC can be placed on top of a $(thing)Bottom Oven$(). These devices will get heat automatically from the bottom oven. They come with a couple restrictions: Each has only 4 slots, and the pot is only used for making soup. It cannot execute regular pot recipes." + } + ], + "read_by_default": true, + "sortnum": 15 +} \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/ovens.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/ovens.json index 3ad43537..8a2711cb 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/ovens.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/ovens.json @@ -6,7 +6,7 @@ "pages": [ { "type": "patchouli:text", - "text": "$(thing)Ovens$() are a great way of cooking lots of food in a way that improves their shelf life. Oven-baked food decays at 90% of the rate of regular food. Ovens are a multiblock structure consisting of a $(thing)Bottom Oven$(), $(thing)Top Oven$(), and optionally $(thing)Chimneys$(). These blocks start off as clay, and must be $(thing)Cured$() by raising their temperature to a certain amount for long enough." + "text": "$(thing)Ovens$() are a great way of cooking lots of food in a way that improves their shelf life. Oven-baked food decays at 90% of the rate of regular food. Ovens are a multiblock structure consisting of a $(thing)Bottom Oven$(), $(thing)Top Oven$(), and optionally $(thing)Chimneys$(). These blocks start off as clay, and must be $(thing)Cured$() by raising their temperature to a certain amount for long enough.$(br)$(l:firmalife:firmalife/oven_appliances)Oven Appliances$() extend oven functionality." }, { "type": "tfc:clay_knapping_recipe", @@ -61,9 +61,9 @@ ] ], "mapping": { - "0": "firmalife:cured_oven_top[facing=south]", - "T": "firmalife:cured_oven_top[facing=south]", - "B": "firmalife:cured_oven_bottom[facing=south]", + "0": "firmalife:cured_oven_top[facing=north]", + "T": "firmalife:cured_oven_top[facing=north]", + "B": "firmalife:cured_oven_bottom[facing=north]", "W": "minecraft:bricks", "C": "firmalife:cured_oven_chimney" } @@ -88,9 +88,9 @@ ] ], "mapping": { - "0": "firmalife:oven_top[facing=south]", - "T": "firmalife:oven_top[facing=south]", - "B": "firmalife:oven_bottom[facing=south]", + "0": "firmalife:oven_top[facing=north]", + "T": "firmalife:oven_top[facing=north]", + "B": "firmalife:oven_bottom[facing=north]", "W": "minecraft:bricks", "C": "firmalife:oven_chimney" } @@ -108,18 +108,8 @@ { "type": "patchouli:text", "text": "Curing Oven blocks is easy, but requires patience. Simply start running your Bottom Oven as you would normally, and then wait. If an oven block is above 600 degrees for about 80 seconds, it will cure itself and any oven blocks around it. The curing effect will pass all the way up chimneys nearby." - }, - { - "type": "patchouli:crafting", - "recipe": "firmalife:crafting/oven_hopper", - "text": "The $(thing)Oven Hopper$() will input logs into any Bottom Oven that it is facing. It holds 16 logs (4 stacks of 4, like a log pile), and its inventory is fed by dropping items in the top. It can also be fed via automation from other mods." - }, - { - "type": "patchouli:crafting", - "recipe": "firmalife:crafting/ashtray", - "text": "The $(thing)Ashtray$() collects $(thing)Wood Ash$() when placed below a $(thing)Bottom Oven Block$(). There is a 0.5 chance it gains ash when fuel is consumed. Ash is extracted with $(item)$(k:key.use)$() and inserted via attacking it." } ], "read_by_default": true, - "sortnum": 13 + "sortnum": 14 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/planters.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/planters.json index e89f718d..2844c36e 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/planters.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/planters.json @@ -71,5 +71,5 @@ } ], "read_by_default": true, - "sortnum": 7 + "sortnum": 8 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/smoking.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/smoking.json index 18093f4a..24d2d1b2 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/smoking.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/smoking.json @@ -45,5 +45,5 @@ } ], "read_by_default": true, - "sortnum": 12 + "sortnum": 13 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/sprinklers.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/sprinklers.json index 48981af6..2eb38017 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/sprinklers.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/sprinklers.json @@ -43,5 +43,5 @@ } ], "read_by_default": true, - "sortnum": 6 + "sortnum": 7 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/stainless_steel.json b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/stainless_steel.json index 5fb5b0a3..5596f9ff 100644 --- a/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/stainless_steel.json +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/stainless_steel.json @@ -28,5 +28,5 @@ } ], "read_by_default": true, - "sortnum": 10 + "sortnum": 11 } \ No newline at end of file diff --git a/src/main/resources/data/firmalife/tags/items/usable_in_stovetop_soup.json b/src/main/resources/data/firmalife/tags/items/usable_in_stovetop_soup.json new file mode 100644 index 00000000..c30763df --- /dev/null +++ b/src/main/resources/data/firmalife/tags/items/usable_in_stovetop_soup.json @@ -0,0 +1,7 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "replace": false, + "values": [ + "#tfc:foods/usable_in_soup" + ] +} \ No newline at end of file diff --git a/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json b/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json index 76852e26..b29a1d2b 100644 --- a/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json +++ b/src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json @@ -39,6 +39,8 @@ "firmalife:hydroponic_planter", "firmalife:vat", "firmalife:squirting_moisture_transducer", + "firmalife:stovetop_grill", + "firmalife:stovetop_pot", "firmalife:sprinkler", "firmalife:dribbler", "firmalife:iron_composter",