diff --git a/resources/generate_book.py b/resources/generate_book.py index 26cd161b..ceccc0ad 100644 --- a/resources/generate_book.py +++ b/resources/generate_book.py @@ -3,6 +3,7 @@ from mcresources.type_definitions import ResourceIdentifier +from constants import FRUITS from patchouli import * from i18n import I18n @@ -199,6 +200,18 @@ def make_book(rm: ResourceManager, i18n: I18n, local_instance: bool = False): text('Butterfly grass will mature over time. When one reaches maturity, it has a chance to spread to surrounding blocks, or turn into something new. Butterfly grass blocks that have been spread by another grass block do not spread anymore.'), block_spotlight('', 'Basil is one of the plants that can be spawned by butterfly grass.', 'firmalife:plant/basil'), crafting('firmalife:crafting/basil_leaves', text_contents='Basil leaves are used in pizza.'), + )), + entry('fruit_trees', 'Firmalife Fruits', 'firmalife:plant/fig_sapling', pages=( + text('Firmalife adds some fruiting plants on top of those added by TFC.'), + text('To improve readability, entries start on the next page.'), + *detail_fruit_tree('cocoa', 'Cocoa trees are used to make $(l:firmalife:firmalife/chocolate)Chocolate$().'), + *detail_fruit_tree('fig'), + )), + entry('chocolate', 'Chocolate', 'firmalife:food/dark_chocolate', pages=( + text('$(thing)Chocolate-making$() takes a few processing steps, for not much of a reward. It\'s important to remember, when playing Firmalife, that being a chocolatier is for your personal enjoyment and pleasure, rather than for trying to extract maximum value from any given input.'), + text('To start chocolate processing, cocoa beans must first be $(thing)roasted$() in an $(l:firmalife:firmalife/ovens)Oven$() to make $(thing)Roasted Cocoa Beans$(). Then, craft the roasted beans with a $(thing)Knife$() to split the beans into $(thing)Cocoa Powder$() and $(thing)Cocoa Powder$().'), + text('The $(l:firmalife:firmalife/mixing_bowl)Mixing Bowl$() is used to mix cocoa powder, butter, and sweetener (sugar or honey) to make $(thing)Chocolate Blends$(). The ratio of cocoa butter to powder determines what comes out:$(br)$(li)1 Powder, 1 Butter, 1 Sweetener: Milk Chocolate$()$(li)2 Powder, 1 Sweetener: Dark Chocolate$()$(li)2 Butter, 1 Sweetener: White Chocolate$()'), + drying_recipe('firmalife:drying/dark_chocolate', 'Finally, chocolate is dried on a $(l:firmalife:firmalife/drying)Drying Mat$() to make $(thing)Chocolate$().') )) )) @@ -219,6 +232,12 @@ def alloy_recipe(title: str, ingot: str, *components: Tuple[str, int, int], text def custom_component(x: int, y: int, class_name: str, data: JsonObject) -> Component: return Component('patchouli:custom', x, y, {'class': 'com.eerussianguy.firmalife.compat.patchouli.' + class_name, **data}) +def detail_fruit_tree(fruit: str, text_contents: str = '', right: Page = None, an: str = 'a') -> Tuple[Page, Page, Page]: + data = FRUITS[fruit] + left = text('$(bold)$(l:the_world/climate#temperature)Temperature$(): %d - %d °C$(br)$(bold)$(l:mechanics/hydration)Rainfall$(): %d - %dmm$(br2)%s' % (data.min_temp, data.max_temp, data.min_rain, data.max_rain, text_contents), title=('%s tree' % fruit).replace('_', ' ').title()).anchor(fruit) + if right is None: + right = multimultiblock('The monthly stages of %s %s tree' % (an, fruit.replace('_', ' ').title()), *[two_tall_block_spotlight('', '', 'firmalife:plant/%s_branch[up=true,down=true]' % fruit, 'firmalife:plant/%s_leaves[lifecycle=%s]' % (fruit, life)) for life in ('dormant', 'healthy', 'flowering', 'fruiting')]) + return left, right, page_break() if __name__ == '__main__': main() 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 a065c5a6..df3e432c 100644 --- a/src/main/java/com/eerussianguy/firmalife/common/blockentities/FLBlockEntities.java +++ b/src/main/java/com/eerussianguy/firmalife/common/blockentities/FLBlockEntities.java @@ -11,7 +11,6 @@ import net.minecraftforge.registries.RegistryObject; import com.eerussianguy.firmalife.FirmaLife; -import com.eerussianguy.firmalife.common.FLTickCounterBlockEntity; import com.eerussianguy.firmalife.common.blocks.FLBlocks; import net.dries007.tfc.common.blockentities.BerryBushBlockEntity; import net.dries007.tfc.util.Helpers; diff --git a/src/main/java/com/eerussianguy/firmalife/common/FLTickCounterBlockEntity.java b/src/main/java/com/eerussianguy/firmalife/common/blockentities/FLTickCounterBlockEntity.java similarity index 91% rename from src/main/java/com/eerussianguy/firmalife/common/FLTickCounterBlockEntity.java rename to src/main/java/com/eerussianguy/firmalife/common/blockentities/FLTickCounterBlockEntity.java index 225c8f02..9e8ae4b6 100644 --- a/src/main/java/com/eerussianguy/firmalife/common/FLTickCounterBlockEntity.java +++ b/src/main/java/com/eerussianguy/firmalife/common/blockentities/FLTickCounterBlockEntity.java @@ -1,4 +1,4 @@ -package com.eerussianguy.firmalife.common; +package com.eerussianguy.firmalife.common.blockentities; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.entity.BlockEntityType; diff --git a/src/main/java/com/eerussianguy/firmalife/common/blockentities/FoodShelfBlockEntity.java b/src/main/java/com/eerussianguy/firmalife/common/blockentities/FoodShelfBlockEntity.java index 31f539ab..c30c3a67 100644 --- a/src/main/java/com/eerussianguy/firmalife/common/blockentities/FoodShelfBlockEntity.java +++ b/src/main/java/com/eerussianguy/firmalife/common/blockentities/FoodShelfBlockEntity.java @@ -100,9 +100,9 @@ public InteractionResult use(Player player, InteractionHand hand) FoodCapability.removeTrait(player.getItemInHand(hand), getFoodTrait()); res = InteractionResult.sidedSuccess(level.isClientSide); } - else if (player.isShiftKeyDown()) + else if (held.isEmpty()) { - ItemStack stack = inventory.extractItem(0, Integer.MAX_VALUE, false); + ItemStack stack = inventory.extractItem(0, player.isShiftKeyDown() ? Integer.MAX_VALUE : 1, false); if (stack.isEmpty()) return InteractionResult.PASS; FoodCapability.removeTrait(stack, getFoodTrait()); ItemHandlerHelper.giveItemToPlayer(player, stack); diff --git a/src/main/java/com/eerussianguy/firmalife/common/capabilities/bee/IBee.java b/src/main/java/com/eerussianguy/firmalife/common/capabilities/bee/IBee.java index 9135e973..fe23588e 100644 --- a/src/main/java/com/eerussianguy/firmalife/common/capabilities/bee/IBee.java +++ b/src/main/java/com/eerussianguy/firmalife/common/capabilities/bee/IBee.java @@ -1,5 +1,7 @@ package com.eerussianguy.firmalife.common.capabilities.bee; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Random; @@ -36,15 +38,11 @@ default void initFreshAbilities(Random random) { final int[] values = BeeAbility.fresh(); - values[random.nextInt(values.length)] = random.nextInt(4) + 1; - values[random.nextInt(values.length)] = random.nextInt(4) + 1; + values[random.nextInt(values.length)] = random.nextInt(3) + 1; + values[random.nextInt(values.length)] = random.nextInt(3) + 1; if (random.nextFloat() < 0.1f) { - values[random.nextInt(values.length)] = random.nextInt(4) + 1; - } - for (int i = 0; i < values.length; i++) - { - values[i] = random.nextInt(4) + 1; + values[random.nextInt(values.length)] = random.nextInt(3) + 1; } setAbilities(values); setHasQueen(true); @@ -57,11 +55,15 @@ default void setAbilitiesFromParents(IBee parent1, IBee parent2, Random random) int mutation = (parent1Abilities[BeeAbility.MUTANT.ordinal()] + parent2Abilities[BeeAbility.MUTANT.ordinal()]) / 2; mutation = Mth.clamp(mutation, 1, 5); - for (BeeAbility ability : BeeAbility.VALUES) + int abilitiesSet = 0; + List abilities = Arrays.asList(BeeAbility.VALUES); + Collections.shuffle(abilities); + for (BeeAbility ability : abilities) { int average = (parent1Abilities[ability.ordinal()] + parent2Abilities[ability.ordinal()]) / 2; - if (average >= 1) + if (average >= 1 && abilitiesSet < 4) { + abilitiesSet++; setAbility(ability, Mth.nextInt(random, average - mutation, average + mutation)); } } diff --git a/src/main/java/com/eerussianguy/firmalife/common/items/HollowShellItem.java b/src/main/java/com/eerussianguy/firmalife/common/items/HollowShellItem.java index 4027357b..fe4a9ef5 100644 --- a/src/main/java/com/eerussianguy/firmalife/common/items/HollowShellItem.java +++ b/src/main/java/com/eerussianguy/firmalife/common/items/HollowShellItem.java @@ -2,19 +2,28 @@ import java.util.function.Supplier; +import com.eerussianguy.firmalife.common.blocks.FLBlocks; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.sounds.SoundSource; import net.minecraft.tags.TagKey; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; import net.minecraftforge.fluids.capability.IFluidHandler; import com.eerussianguy.firmalife.common.misc.FLSounds; -import net.dries007.tfc.common.items.DiscreteFluidContainerItem; + +import net.dries007.tfc.common.fluids.FluidHelpers; import net.dries007.tfc.common.items.FluidContainerItem; +import net.dries007.tfc.util.Helpers; public class HollowShellItem extends FluidContainerItem { @@ -26,6 +35,27 @@ public HollowShellItem(Properties properties, Supplier capacity, TagKey @Override protected InteractionResultHolder afterFillFailed(IFluidHandler handler, Level level, Player player, ItemStack stack, InteractionHand hand) { + if (player.isShiftKeyDown()) + { + final BlockHitResult hit = Helpers.rayTracePlayer(level, player, ClipContext.Fluid.NONE); + if (hit.getType() != HitResult.Type.MISS && hit.getDirection() == Direction.UP) + { + final BlockPos pos = hit.getBlockPos().above(); + BlockState state = FLBlocks.HOLLOW_SHELL.get().defaultBlockState(); + if (state.canSurvive(level, pos)) + { + Fluid fluid = level.getFluidState(pos).getType(); + state = FluidHelpers.fillWithFluid(state, fluid); + if (state != null) + { + Helpers.playSound(level, pos, state.getSoundType().getPlaceSound()); + level.setBlockAndUpdate(pos, state); + stack.shrink(1); + return InteractionResultHolder.consume(stack); + } + } + } + } level.playSound(player, player.blockPosition(), FLSounds.HOLLOW_SHELL_BLOW.get(), SoundSource.PLAYERS, 1.0F, 0.8F + (float)(player.getLookAngle().y / 2.0)); return InteractionResultHolder.success(stack); } 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 new file mode 100644 index 00000000..5d2ddc59 --- /dev/null +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/chocolate.json @@ -0,0 +1,27 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "name": "Chocolate", + "category": "firmalife:firmalife", + "icon": "firmalife:food/dark_chocolate", + "pages": [ + { + "type": "patchouli:text", + "text": "$(thing)Chocolate-making$() takes a few processing steps, for not much of a reward. It's important to remember, when playing Firmalife, that being a chocolatier is for your personal enjoyment and pleasure, rather than for trying to extract maximum value from any given input." + }, + { + "type": "patchouli:text", + "text": "To start chocolate processing, cocoa beans must first be $(thing)roasted$() in an $(l:firmalife:firmalife/ovens)Oven$() to make $(thing)Roasted Cocoa Beans$(). Then, craft the roasted beans with a $(thing)Knife$() to split the beans into $(thing)Cocoa Powder$() and $(thing)Cocoa Powder$()." + }, + { + "type": "patchouli:text", + "text": "The $(l:firmalife:firmalife/mixing_bowl)Mixing Bowl$() is used to mix cocoa powder, butter, and sweetener (sugar or honey) to make $(thing)Chocolate Blends$(). The ratio of cocoa butter to powder determines what comes out:$(br)$(li)1 Powder, 1 Butter, 1 Sweetener: Milk Chocolate$()$(li)2 Powder, 1 Sweetener: Dark Chocolate$()$(li)2 Butter, 1 Sweetener: White Chocolate$()" + }, + { + "type": "firmalife:drying_recipe", + "recipe": "firmalife:drying/dark_chocolate", + "text": "Finally, chocolate is dried on a $(l:firmalife:firmalife/drying)Drying Mat$() to make $(thing)Chocolate$()." + } + ], + "read_by_default": true, + "sortnum": 19 +} \ 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 new file mode 100644 index 00000000..98b4a0c9 --- /dev/null +++ b/src/main/resources/data/firmalife/patchouli_books/field_guide/en_us/entries/firmalife/fruit_trees.json @@ -0,0 +1,178 @@ +{ + "__comment__": "This file was automatically created by mcresources", + "name": "Firmalife Fruits", + "category": "firmalife:firmalife", + "icon": "firmalife:plant/fig_sapling", + "pages": [ + { + "type": "patchouli:text", + "text": "Firmalife adds some fruiting plants on top of those added by TFC." + }, + { + "type": "patchouli:text", + "text": "To improve readability, entries start on the next page." + }, + { + "type": "patchouli:text", + "anchor": "cocoa", + "text": "$(bold)$(l:the_world/climate#temperature)Temperature$(): 20 - 35 °C$(br)$(bold)$(l:mechanics/hydration)Rainfall$(): 220 - 400mm$(br2)Cocoa trees are used to make $(l:firmalife:firmalife/chocolate)Chocolate$().", + "title": "Cocoa Tree" + }, + { + "type": "tfc:multimultiblock", + "text": "The monthly stages of a Cocoa tree", + "multiblocks": [ + { + "pattern": [ + [ + "X" + ], + [ + "Y" + ], + [ + "0" + ] + ], + "mapping": { + "X": "firmalife:plant/cocoa_leaves[lifecycle=dormant]", + "Y": "firmalife:plant/cocoa_branch[up=true,down=true]" + } + }, + { + "pattern": [ + [ + "X" + ], + [ + "Y" + ], + [ + "0" + ] + ], + "mapping": { + "X": "firmalife:plant/cocoa_leaves[lifecycle=healthy]", + "Y": "firmalife:plant/cocoa_branch[up=true,down=true]" + } + }, + { + "pattern": [ + [ + "X" + ], + [ + "Y" + ], + [ + "0" + ] + ], + "mapping": { + "X": "firmalife:plant/cocoa_leaves[lifecycle=flowering]", + "Y": "firmalife:plant/cocoa_branch[up=true,down=true]" + } + }, + { + "pattern": [ + [ + "X" + ], + [ + "Y" + ], + [ + "0" + ] + ], + "mapping": { + "X": "firmalife:plant/cocoa_leaves[lifecycle=fruiting]", + "Y": "firmalife:plant/cocoa_branch[up=true,down=true]" + } + } + ] + }, + { + "type": "patchouli:text", + "anchor": "fig", + "text": "$(bold)$(l:the_world/climate#temperature)Temperature$(): 20 - 35 °C$(br)$(bold)$(l:mechanics/hydration)Rainfall$(): 125 - 215mm$(br2)", + "title": "Fig Tree" + }, + { + "type": "tfc:multimultiblock", + "text": "The monthly stages of a Fig tree", + "multiblocks": [ + { + "pattern": [ + [ + "X" + ], + [ + "Y" + ], + [ + "0" + ] + ], + "mapping": { + "X": "firmalife:plant/fig_leaves[lifecycle=dormant]", + "Y": "firmalife:plant/fig_branch[up=true,down=true]" + } + }, + { + "pattern": [ + [ + "X" + ], + [ + "Y" + ], + [ + "0" + ] + ], + "mapping": { + "X": "firmalife:plant/fig_leaves[lifecycle=healthy]", + "Y": "firmalife:plant/fig_branch[up=true,down=true]" + } + }, + { + "pattern": [ + [ + "X" + ], + [ + "Y" + ], + [ + "0" + ] + ], + "mapping": { + "X": "firmalife:plant/fig_leaves[lifecycle=flowering]", + "Y": "firmalife:plant/fig_branch[up=true,down=true]" + } + }, + { + "pattern": [ + [ + "X" + ], + [ + "Y" + ], + [ + "0" + ] + ], + "mapping": { + "X": "firmalife:plant/fig_leaves[lifecycle=fruiting]", + "Y": "firmalife:plant/fig_branch[up=true,down=true]" + } + } + ] + } + ], + "read_by_default": true, + "sortnum": 18 +} \ No newline at end of file