Esempio n. 1
0
def generate(rm: ResourceManager):
    # Metal Items

    for metal, metal_data in METALS.items():

        # Metal
        rm.data(
            ('tfc', 'metals', metal), {
                'tier': metal_data.tier,
                'fluid': 'tfc:metal/%s' % metal,
                'melt_temperature': metal_data.melt_temperature,
                'heat_capacity': metal_data.heat_capacity
            })

        # Metal Items and Blocks
        for item, item_data in METAL_ITEMS_AND_BLOCKS.items():
            if item_data.type in metal_data.types or item_data.type == 'all':
                if item_data.tag is not None:
                    rm.item_tag(item_data.tag + '/' + metal,
                                'tfc:metal/%s/%s' % (item, metal))
                    ingredient = utils.item_stack('#%s/%s' %
                                                  (item_data.tag, metal))
                else:
                    ingredient = utils.item_stack('tfc:metal/%s/%s' %
                                                  (item, metal))

                item_heat(rm, ('metal', metal + '_' + item), ingredient,
                          metal_data.heat_capacity,
                          metal_data.melt_temperature)
                if 'tool' in metal_data.types and item == 'fishing_rod':
                    rm.item_tag('forge:fishing_rods',
                                'tfc:metal/%s/%s' % (item, metal))

    for ore, ore_data in ORES.items():
        if ore_data.metal and ore_data.graded:
            metal_data = METALS[ore_data.metal]
            item_heat(rm, ('ore', ore), [
                'tfc:ore/small_%s' % ore,
                'tfc:ore/normal_%s' % ore,
                'tfc:ore/poor_%s' % ore,
                'tfc:ore/rich_%s' % ore
            ], metal_data.heat_capacity, int(metal_data.melt_temperature))

    # Item Heats

    item_heat(rm, 'wrought_iron_grill', 'tfc:wrought_iron_grill', 0.35, 1535)
    item_heat(rm, 'stick', '#forge:rods/wooden', 0.3)
    item_heat(rm, 'stick_bunch', 'tfc:stick_bunch', 0.05)
    item_heat(rm, 'glass_shard', 'tfc:glass_shard', 1)
    item_heat(rm, 'sand', '#forge:sand', 0.8)
    item_heat(rm, 'ceramic_unfired_brick', 'tfc:ceramic/unfired_brick',
              POTTERY_HC)
    item_heat(rm, 'ceramic_unfired_flower_pot',
              'tfc:ceramic/unfired_flower_pot', POTTERY_HC)
    item_heat(rm, 'ceramic_unfired_jug', 'tfc:ceramic/unfired_jug', POTTERY_HC)
    item_heat(rm, 'terracotta', [
        'minecraft:terracotta',
        *['minecraft:%s_terracotta' % color for color in COLORS]
    ], 0.8)
    item_heat(rm, 'dough', ['tfc:food/%s_dough' % grain for grain in GRAINS],
              1)
    item_heat(rm, 'meat', ['tfc:food/%s' % meat for meat in MEATS], 1)
    item_heat(rm, 'edible_plants',
              ['tfc:plant/%s' % plant
               for plant in SEAWEED] + ['tfc:plant/giant_kelp_flower'], 1)

    for pottery in SIMPLE_POTTERY:
        item_heat(rm, 'unfired_' + pottery, 'tfc:ceramic/unfired_' + pottery,
                  POTTERY_HC)

    for item, item_data in METAL_ITEMS.items():
        if item_data.mold:
            item_heat(rm, 'unfired_%s_mold' % item,
                      'tfc:ceramic/unfired_%s_mold' % item, POTTERY_HC)
            # No need to do fired molds, as they have their own capability implementation

    # Supports

    for wood in WOODS:
        rm.data(
            ('tfc', 'supports', wood), {
                'ingredient': 'tfc:wood/horizontal_support/%s' % wood,
                'support_up': 1,
                'support_down': 1,
                'support_horizontal': 4
            })

    # Fuels

    for wood, wood_data in WOODS.items():
        fuel_item(rm, wood + '_log',
                  ['tfc:wood/log/' + wood, 'tfc:wood/wood/' + wood],
                  wood_data.duration, wood_data.temp)

    fuel_item(rm, 'coal', ['minecraft:coal', 'tfc:ore/bituminous_coal'], 2200,
              1415)
    fuel_item(rm, 'lignite', 'tfc:ore/lignite', 2200, 1350)
    fuel_item(rm, 'charcoal', 'minecraft:charcoal', 1800, 1350)
    fuel_item(rm, 'peat', 'tfc:peat', 2500, 600)
    fuel_item(rm, 'stick_bundle', 'tfc:stick_bundle', 600, 900)

    # =========
    # ITEM TAGS
    # =========

    rm.item_tag('forge:ingots/cast_iron', 'minecraft:iron_ingot')
    rm.item_tag('firepit_sticks', '#forge:rods/wooden')
    rm.item_tag('firepit_kindling', 'tfc:straw', 'minecraft:paper',
                'minecraft:book', 'tfc:groundcover/pinecone')
    rm.item_tag('starts_fires_with_durability', 'minecraft:flint_and_steel')
    rm.item_tag('starts_fires_with_items', 'minecraft:fire_charge')
    rm.item_tag('handstone', 'tfc:handstone')
    rm.item_tag('high_quality_cloth', 'tfc:silk_cloth', 'tfc:wool_cloth')
    rm.item_tag('minecraft:stone_pressure_plates',
                'minecraft:stone_pressure_plate',
                'minecraft:polished_blackstone_pressure_plate')
    rm.item_tag('axes_that_log', '#tfc:axes')
    rm.item_tag('extinguisher', '#tfc:shovels')
    rm.item_tag('forge:shears', '#tfc:shears')  # forge tag includes TFC shears
    rm.item_tag('minecraft:coals', 'tfc:ore/bituminous_coal',
                'tfc:ore/lignite')
    rm.item_tag('forge_fuel', '#minecraft:coals')
    rm.item_tag('firepit_fuel', '#minecraft:logs', 'tfc:peat',
                'tfc:peat_grass', 'tfc:stick_bundle')
    rm.item_tag('bloomery_fuel', 'minecraft:charcoal')
    rm.item_tag('log_pile_logs', 'tfc:stick_bundle')
    rm.item_tag('pit_kiln_straw', 'tfc:straw')
    rm.item_tag('firepit_logs', '#minecraft:logs')
    rm.item_tag('log_pile_logs', '#minecraft:logs')
    rm.item_tag('pit_kiln_logs', '#minecraft:logs')
    rm.item_tag('can_be_lit_on_torch', '#forge:rods/wooden')
    rm.item_tag('mortar', 'tfc:mortar')
    rm.item_tag('thatch_bed_hides', 'tfc:large_raw_hide',
                'tfc:large_sheepskin_hide')
    rm.item_tag('scrapable', 'tfc:large_soaked_hide', 'tfc:medium_soaked_hide',
                'tfc:small_soaked_hide')
    rm.item_tag('clay_knapping', 'minecraft:clay_ball')
    rm.item_tag('fire_clay_knapping', 'tfc:fire_clay')
    rm.item_tag('leather_knapping', 'minecraft:leather')
    rm.item_tag('knapping_any', '#tfc:clay_knapping',
                '#tfc:fire_clay_knapping', '#tfc:leather_knapping',
                '#tfc:rock_knapping')
    rm.item_tag('forge:gems/diamond', 'tfc:gem/diamond')
    rm.item_tag('forge:gems/lapis', 'tfc:gem/lapis_lazuli')
    rm.item_tag('forge:gems/emerald', 'tfc:gem/emerald')
    rm.item_tag('bush_cutting_tools', '#forge:shears', '#tfc:knives')
    rm.item_tag('minecraft:fishes', 'tfc:food/cod', 'tfc:food/cooked_cod',
                'tfc:food/salmon', 'tfc:food/cooked_salmon',
                'tfc:food/tropical_fish', 'tfc:food/cooked_tropical_fish',
                'tfc:food/bluegill', 'tfc:food/cooked_bluegill')

    for gem in GEMS:
        rm.item_tag('forge:gems', 'tfc:gem/' + gem)

    for wood in WOODS.keys():
        rm.item_tag('minecraft:logs', 'tfc:wood/log/%s' % wood,
                    'tfc:wood/wood/%s' % wood,
                    'tfc:wood/stripped_log/%s' % wood,
                    'tfc:wood/stripped_wood/%s' % wood)
        rm.item_tag('twigs', 'tfc:wood/twig/%s' % wood)
        rm.item_tag('lumber', 'tfc:wood/lumber/%s' % wood)

    for category in ROCK_CATEGORIES:  # Rock (Category) Tools
        for tool in ROCK_CATEGORY_ITEMS:
            rm.item_tag(TOOL_TAGS[tool], 'tfc:stone/%s/%s' % (tool, category))

    for metal, metal_data in METALS.items():  # Metal Tools
        if 'tool' in metal_data.types:
            for tool_type, tool_tag in TOOL_TAGS.items():
                rm.item_tag(tool_tag, 'tfc:metal/%s/%s' % (tool_type, metal))

    # Blocks and Items
    block_and_item_tag(
        rm, 'forge:sand', '#minecraft:sand'
    )  # Forge doesn't reference the vanilla tag for some reason

    # Sand
    for color in SAND_BLOCK_TYPES:
        block_and_item_tag(rm, 'minecraft:sand', 'tfc:sand/%s' % color)

    # ==========
    # BLOCK TAGS
    # ==========

    rm.block_tag('tree_grows_on', 'minecraft:grass_block', '#forge:dirt',
                 '#tfc:grass')
    rm.block_tag('supports_landslide', 'minecraft:dirt_path')
    rm.block_tag('bush_plantable_on', 'minecraft:grass_block', '#forge:dirt',
                 '#tfc:grass')
    rm.block_tag('small_spike', 'tfc:calcite')
    rm.block_tag('sea_bush_plantable_on', '#forge:dirt', '#minecraft:sand',
                 '#forge:gravel')
    rm.block_tag('creeping_plantable_on', 'minecraft:grass_block',
                 '#tfc:grass', '#minecraft:base_stone_overworld',
                 '#minecraft:logs')
    rm.block_tag('minecraft:bamboo_plantable_on', '#tfc:grass')
    rm.block_tag('minecraft:climbable', 'tfc:plant/hanging_vines',
                 'tfc:plant/hanging_vines_plant', 'tfc:plant/liana',
                 'tfc:plant/liana_plant')
    rm.block_tag('kelp_tree', 'tfc:plant/giant_kelp_flower',
                 'tfc:plant/giant_kelp_plant')
    rm.block_tag('kelp_flower', 'tfc:plant/giant_kelp_flower')
    rm.block_tag('kelp_branch', 'tfc:plant/giant_kelp_plant')
    rm.block_tag('lit_by_dropped_torch', 'tfc:log_pile', 'tfc:thatch',
                 'tfc:pit_kiln')
    rm.block_tag('charcoal_cover_whitelist', 'tfc:log_pile',
                 'tfc:charcoal_pile', 'tfc:burning_log_pile')
    rm.block_tag('forge_invisible_whitelist', 'tfc:crucible')
    rm.block_tag('any_spreading_bush', '#tfc:spreading_bush')
    rm.block_tag('thorny_bushes', 'tfc:plant/blackberry_bush',
                 'tfc:plant/raspberry_bush')
    rm.block_tag('logs_that_log', '#minecraft:logs')
    rm.block_tag('scraping_surface', '#minecraft:logs')
    rm.block_tag('forge:sand',
                 '#minecraft:sand')  # Forge doesn't reference the vanilla tag
    rm.block_tag('thatch_bed_thatch', 'tfc:thatch')
    rm.block_tag('snow', 'minecraft:snow', 'minecraft:snow_block',
                 'tfc:snow_pile')
    rm.block_tag('tfc:forge_insulation', '#forge:stone', '#forge:cobblestone',
                 '#forge:stone_bricks', '#forge:smooth_stone')
    rm.block_tag('minecraft:valid_spawn',
                 *['tfc:grass/%s' % v for v in SOIL_BLOCK_VARIANTS],
                 *['tfc:sand/%s' % c for c in SAND_BLOCK_TYPES],
                 *['tfc:rock/raw/%s' % r for r in ROCKS.keys()
                   ])  # Valid spawn tag - grass, sand, or raw rock
    rm.block_tag('forge:dirt',
                 *['tfc:dirt/%s' % v for v in SOIL_BLOCK_VARIANTS])
    rm.block_tag('prospectable', '#forge:ores')

    for wood in WOODS.keys():
        rm.block_tag('lit_by_dropped_torch', 'tfc:wood/fallen_leaves/' + wood)

    for plant, plant_data in PLANTS.items():  # Plants
        rm.block_tag('plant', 'tfc:plant/%s' % plant)
        if plant_data.type in {'standard', 'short_grass', 'creeping'}:
            rm.block_tag('can_be_snow_piled', 'tfc:plant/%s' % plant)

    # Rocks
    for rock, rock_data in ROCKS.items():

        def block(block_type: str):
            return 'tfc:rock/%s/%s' % (block_type, rock)

        block_and_item_tag(rm, 'forge:gravel', 'tfc:rock/gravel/%s' % rock)
        rm.block_tag('forge:stone', block('raw'), block('hardened'))
        rm.block_tag('forge:cobblestone', block('cobble'),
                     block('mossy_cobble'))
        rm.block_tag('minecraft:base_stone_overworld', block('raw'),
                     block('hardened'))
        rm.block_tag('forge:stone_bricks', block('bricks'),
                     block('mossy_bricks'), block('cracked_bricks'))
        rm.block_tag('forge:smooth_stone', block('smooth'))
        rm.block_tag('tfc:breaks_when_isolated', block('raw'))
        rm.block_tag('minecraft:stone_pressure_plates',
                     block('pressure_plate'))

        rm.item_tag('forge:smooth_stone', block('smooth'))
        rm.item_tag('forge:smooth_stone_slab',
                    'tfc:rock/smooth/%s_slab' % rock)
        rm.item_tag('tfc:rock_knapping', block('loose'))
        rm.item_tag('tfc:%s_rock' % rock_data.category, block('loose'))
        rm.item_tag('minecraft:stone_pressure_plates', block('pressure_plate'))

        if rock in ['chalk', 'dolomite', 'limestone', 'marble']:
            rm.item_tag('tfc:fluxstone', block('loose'))

    for plant in PLANTS.keys():
        rm.block_tag('can_be_snow_piled', 'tfc:plant/%s' % plant)

    # Ore tags
    for ore, data in ORES.items():
        if data.tag not in DEFAULT_FORGE_ORE_TAGS:
            rm.block_tag('forge:ores', '#forge:ores/%s' % data.tag)
        if data.graded:  # graded ores -> each grade is declared as a TFC tag, then added to the forge tag
            rm.block_tag('forge:ores/%s' % data.tag,
                         '#tfc:ores/%s/poor' % data.tag,
                         '#tfc:ores/%s/normal' % data.tag,
                         '#tfc:ores/%s/rich' % data.tag)
        for rock in ROCKS.keys():
            if data.graded:
                rm.block_tag('ores/%s/poor' % data.tag,
                             'tfc:ore/poor_%s/%s' % (ore, rock))
                rm.block_tag('ores/%s/normal' % data.tag,
                             'tfc:ore/normal_%s/%s' % (ore, rock))
                rm.block_tag('ores/%s/rich' % data.tag,
                             'tfc:ore/rich_%s/%s' % (ore, rock))
            else:
                rm.block_tag('forge:ores/%s' % data.tag,
                             'tfc:ore/%s/%s' % (ore, rock))

    # can_carve Tag
    for rock in ROCKS.keys():
        for variant in ('raw', 'hardened', 'gravel', 'cobble'):
            rm.block_tag('can_carve', 'tfc:rock/%s/%s' % (variant, rock))
    for sand in SAND_BLOCK_TYPES:
        rm.block_tag('can_carve', 'tfc:sand/%s' % sand,
                     'tfc:raw_sandstone/%s' % sand)
    for soil in SOIL_BLOCK_VARIANTS:
        rm.block_tag('can_carve', 'tfc:dirt/%s' % soil, 'tfc:grass/%s' % soil)

    # Harvest Tool + Level Tags

    rm.block_tag('needs_stone_tool', '#forge:needs_wood_tool')
    rm.block_tag('needs_copper_tool', '#minecraft:needs_stone_tool')
    rm.block_tag('needs_wrought_iron_tool', '#minecraft:needs_iron_tool')
    rm.block_tag('needs_steel_tool', '#minecraft:needs_diamond_tool')
    rm.block_tag('needs_colored_steel_tool', '#forge:needs_netherite_tool')

    rm.block_tag('minecraft:mineable/hoe', '#tfc:mineable_with_sharp_tool')
    rm.block_tag('tfc:mineable_with_knife', '#tfc:mineable_with_sharp_tool')
    rm.block_tag('tfc:mineable_with_scythe', '#tfc:mineable_with_sharp_tool')

    rm.block_tag('forge:needs_wood_tool')
    rm.block_tag('forge:needs_netherite_tool')

    for ore, data in ORES.items():
        for rock in ROCKS.keys():
            if data.graded:
                rm.block_tag('needs_%s_tool' % data.required_tool,
                             'tfc:ore/poor_%s/%s' % (ore, rock),
                             'tfc:ore/normal_%s/%s' % (ore, rock),
                             'tfc:ore/rich_%s/%s' % (ore, rock))
            else:
                rm.block_tag('needs_%s_tool' % data.required_tool,
                             'tfc:ore/%s/%s' % (ore, rock))

    rm.block_tag(
        'minecraft:mineable/shovel', *[
            *[
                'tfc:%s/%s' % (soil, variant) for soil in SOIL_BLOCK_TYPES
                for variant in SOIL_BLOCK_VARIANTS
            ], 'tfc:peat', 'tfc:peat_grass',
            *['tfc:sand/%s' % sand
              for sand in SAND_BLOCK_TYPES], 'tfc:snow_pile',
            *['tfc:rock/gravel/%s' % rock
              for rock in ROCKS.keys()], 'tfc:aggregate',
            'tfc:fire_clay_block', 'tfc:charcoal_pile', 'tfc:charcoal_forge'
        ])
    rm.block_tag(
        'minecraft:mineable/pickaxe', *[
            *[
                'tfc:%s_sandstone/%s' % (variant, sand)
                for variant in SANDSTONE_BLOCK_TYPES
                for sand in SAND_BLOCK_TYPES
            ], *[
                'tfc:%s_sandstone/%s_%s' % (variant, sand, suffix)
                for variant in SANDSTONE_BLOCK_TYPES
                for sand in SAND_BLOCK_TYPES
                for suffix in ('slab', 'stairs', 'wall')
            ], 'tfc:icicle', 'tfc:calcite', *[
                'tfc:ore/%s/%s' % (ore, rock)
                for ore, ore_data in ORES.items()
                for rock in ROCKS.keys() if not ore_data.graded
            ], *[
                'tfc:ore/%s_%s/%s' % (grade, ore, rock)
                for ore, ore_data in ORES.items() for rock in ROCKS.keys()
                for grade in ORE_GRADES.keys() if ore_data.graded
            ], *[
                'tfc:ore/small_%s' % ore
                for ore, ore_data in ORES.items() if ore_data.graded
            ], *[
                'tfc:rock/%s/%s' % (variant, rock)
                for variant in ('raw', 'hardened', 'smooth', 'cobble',
                                'bricks', 'spike', 'cracked_bricks',
                                'mossy_bricks', 'mossy_cobble', 'chiseled',
                                'loose', 'pressure_plate', 'button')
                for rock in ROCKS.keys()
            ], *[
                'tfc:rock/%s/%s_%s' % (variant, rock, suffix)
                for variant in ('raw', 'smooth', 'cobble', 'bricks',
                                'cracked_bricks', 'mossy_bricks',
                                'mossy_cobble') for rock in ROCKS.keys()
                for suffix in ('slab', 'stairs', 'wall')
            ], *[
                'tfc:rock/anvil/%s' % rock
                for rock, rock_data in ROCKS.items()
                if rock_data.category == 'igneous_intrusive'
                or rock_data.category == 'igneous_extrusive'
            ], *[
                'tfc:metal/%s/%s' % (variant, metal)
                for variant, variant_data in METAL_BLOCKS.items()
                for metal, metal_data in METALS.items()
                if variant_data.type in metal_data.types
            ], *[
                'tfc:coral/%s_%s' % (color, variant) for color in CORALS
                for variant in CORAL_BLOCKS
            ], 'tfc:alabaster/raw/alabaster',
            'tfc:alabaster/raw/alabaster_bricks',
            'tfc:alabaster/raw/polished_alabaster', *[
                'tfc:alabaster/stained/%s%s' % (color, variant)
                for color in COLORS for variant in
                ('_raw_alabaster', '_alabaster_bricks', '_polished_alabaster',
                 '_alabaster_bricks_slab', '_alabaster_bricks_stairs',
                 '_alabaster_bricks_wall', '_polished_alabaster_slab',
                 '_polished_alabaster_stairs', '_polished_alabaster_wall')
            ], 'tfc:fire_bricks', 'tfc:quern'
        ])
    rm.block_tag(
        'minecraft:mineable/axe', *[
            *[
                'tfc:wood/%s/%s' % (variant, wood)
                for variant in ('log', 'stripped_log', 'wood', 'stripped_wood',
                                'planks', 'twig', 'vertical_support',
                                'horizontal_support') for wood in WOODS.keys()
            ], *[
                'tfc:wood/planks/%s_%s' % (wood, variant)
                for variant in ('bookshelf', 'door', 'trapdoor', 'fence',
                                'log_fence', 'fence_gate', 'button',
                                'pressure_plate', 'slab', 'stairs',
                                'tool_rack', 'workbench')
                for wood in WOODS.keys()
            ], *['tfc:plant/%s_branch' % tree for tree in NORMAL_FRUIT_TREES],
            *[
                'tfc:plant/%s_growing_branch' % tree
                for tree in NORMAL_FRUIT_TREES
            ], 'tfc:plant/banana_plant', 'tfc:log_pile', 'tfc:burning_log_pile'
        ])
    rm.block_tag(
        'tfc:mineable_with_sharp_tool', *[
            *[
                'tfc:wood/%s/%s' % (variant, wood)
                for variant in ('leaves', 'sapling', 'fallen_leaves')
                for wood in WOODS.keys()
            ], *['tfc:plant/%s' % plant for plant in PLANTS.keys()],
            *['tfc:plant/%s' % plant
              for plant in UNIQUE_PLANTS], 'tfc:sea_pickle', *[
                  'tfc:plant/%s_bush' % bush
                  for bush in ('snowberry', 'bunchberry', 'gooseberry',
                               'cloudberry', 'strawberry', 'wintergreen_berry')
              ], *[
                  'tfc:plant/%s_bush%s' % (bush, suffix)
                  for bush in ('blackberry', 'raspberry', 'blueberry',
                               'elderberry') for suffix in ('', '_cane')
              ], 'tfc:plant/cranberry_bush', 'tfc:plant/dead_berry_bush',
            'tfc:plant/dead_cane',
            *['tfc:plant/%s_leaves' % tree for tree in NORMAL_FRUIT_TREES],
            *['tfc:plant/%s_sapling' % tree for tree in NORMAL_FRUIT_TREES],
            'tfc:plant/banana_sapling', 'tfc:thatch', 'tfc:thatch_bed'
        ])

    # ==========
    # FLUID TAGS
    # ==========

    rm.fluid_tag('fluid_ingredients', 'minecraft:water', 'tfc:salt_water',
                 'tfc:spring_water')
    rm.fluid_tag('drinkables', 'minecraft:water', 'tfc:salt_water',
                 'tfc:river_water')
    rm.fluid_tag('hydrating', 'minecraft:water', 'tfc:river_water')

    rm.fluid_tag('usable_in_pot', '#tfc:fluid_ingredients')
    rm.fluid_tag('usable_in_jug', '#tfc:drinkables')

    # Item Sizes

    # todo: specific item size definitions for a whole bunch of items that aren't naturally assigned
    item_size(rm, 'logs', '#minecraft:logs', Size.very_large, Weight.medium)

    # Food

    food_item(rm,
              'banana',
              'tfc:food/banana',
              Category.fruit,
              4,
              0.2,
              0,
              2,
              fruit=1)
    food_item(rm,
              'blackberry',
              'tfc:food/blackberry',
              Category.fruit,
              4,
              0.2,
              5,
              4.9,
              fruit=0.75)
    food_item(rm,
              'blueberry',
              'tfc:food/blueberry',
              Category.fruit,
              4,
              0.2,
              5,
              4.9,
              fruit=0.75)
    food_item(rm,
              'bunchberry',
              'tfc:food/bunchberry',
              Category.fruit,
              4,
              0.5,
              5,
              4.9,
              fruit=0.75)
    food_item(rm,
              'cherry',
              'tfc:food/cherry',
              Category.fruit,
              4,
              0.2,
              5,
              4,
              fruit=1)
    food_item(rm,
              'cloudberry',
              'tfc:food/cloudberry',
              Category.fruit,
              4,
              0.5,
              5,
              4.9,
              fruit=0.75)
    food_item(rm,
              'cranberry',
              'tfc:food/cranberry',
              Category.fruit,
              4,
              0.2,
              5,
              1.8,
              fruit=1)
    food_item(rm,
              'elderberry',
              'tfc:food/elderberry',
              Category.fruit,
              4,
              0.2,
              5,
              4.9,
              fruit=1)
    food_item(rm,
              'gooseberry',
              'tfc:food/gooseberry',
              Category.fruit,
              4,
              0.5,
              5,
              4.9,
              fruit=0.75)
    food_item(rm,
              'green_apple',
              'tfc:food/green_apple',
              Category.fruit,
              4,
              0.5,
              0,
              2.5,
              fruit=1)
    food_item(rm,
              'lemon',
              'tfc:food/lemon',
              Category.fruit,
              4,
              0.2,
              5,
              2,
              fruit=0.75)
    food_item(rm,
              'olive',
              'tfc:food/olive',
              Category.fruit,
              4,
              0.2,
              0,
              1.6,
              fruit=1)
    food_item(rm,
              'orange',
              'tfc:food/orange',
              Category.fruit,
              4,
              0.5,
              10,
              2.2,
              fruit=0.5)
    food_item(rm,
              'peach',
              'tfc:food/peach',
              Category.fruit,
              4,
              0.5,
              10,
              2.8,
              fruit=0.5)
    food_item(rm,
              'plum',
              'tfc:food/plum',
              Category.fruit,
              4,
              0.5,
              5,
              2.8,
              fruit=0.75)
    food_item(rm,
              'raspberry',
              'tfc:food/raspberry',
              Category.fruit,
              4,
              0.5,
              5,
              4.9,
              fruit=0.75)
    food_item(rm,
              'red_apple',
              'tfc:food/red_apple',
              Category.fruit,
              4,
              0.5,
              0,
              1.7,
              fruit=1)
    food_item(rm,
              'snowberry',
              'tfc:food/snowberry',
              Category.fruit,
              4,
              0.2,
              5,
              4.9,
              fruit=1)
    food_item(rm,
              'strawberry',
              'tfc:food/strawberry',
              Category.fruit,
              4,
              0.5,
              10,
              4.9,
              fruit=0.5)
    food_item(rm,
              'wintergreen_berry',
              'tfc:food/wintergreen_berry',
              Category.fruit,
              4,
              0.2,
              5,
              4.9,
              fruit=1)
    food_item(rm, 'barley', 'tfc:food/barley', Category.grain, 4, 0, 0, 2)
    food_item(rm, 'barley_grain', 'tfc:food/barley_grain', Category.grain, 4,
              0, 0, 0.25)
    food_item(rm, 'barley_flour', 'tfc:food/barley_flour', Category.grain, 4,
              0, 0, 0.5)
    food_item(rm, 'barley_dough', 'tfc:food/barley_dough', Category.grain, 4,
              0, 0, 3)
    food_item(rm,
              'barley_bread',
              'tfc:food/barley_bread',
              Category.bread,
              4,
              1,
              0,
              1,
              grain=1.5)
    food_item(rm, 'maize', 'tfc:food/maize', Category.grain, 4, 0, 0, 2)
    food_item(rm, 'maize_grain', 'tfc:food/maize_grain', Category.grain, 4,
              0.5, 0, 0.25)
    food_item(rm, 'maize_flour', 'tfc:food/maize_flour', Category.grain, 4, 0,
              0, 0.5)
    food_item(rm, 'maize_dough', 'tfc:food/maize_dough', Category.grain, 4, 0,
              0, 3)
    food_item(rm,
              'maize_bread',
              'tfc:food/maize_bread',
              Category.bread,
              4,
              1,
              0,
              1,
              grain=1)
    food_item(rm, 'oat', 'tfc:food/oat', Category.grain, 4, 0, 0, 2)
    food_item(rm, 'oat_grain', 'tfc:food/oat_grain', Category.grain, 4, 0.5, 0,
              0.25)
    food_item(rm, 'oat_flour', 'tfc:food/oat_flour', Category.grain, 4, 0, 0,
              0.5)
    food_item(rm, 'oat_dough', 'tfc:food/oat_dough', Category.grain, 4, 0, 0,
              3)
    food_item(rm,
              'oat_bread',
              'tfc:food/oat_bread',
              Category.bread,
              4,
              1,
              0,
              1,
              grain=1)
    # todo: figure out what to do with rice. thinking rice -> grain -> cooked rice in a pot recipe? so remove flour/dough/bread for this one
    food_item(rm, 'rice', 'tfc:food/rice', Category.grain, 4, 0, 0, 2)
    food_item(rm, 'rice_grain', 'tfc:food/rice_grain', Category.grain, 4, 0.5,
              0, 0.25)
    food_item(rm, 'rice_flour', 'tfc:food/rice_flour', Category.grain, 4, 0, 0,
              0.5)
    food_item(rm, 'rice_dough', 'tfc:food/rice_dough', Category.grain, 4, 0, 0,
              3)
    food_item(rm,
              'rice_bread',
              'tfc:food/rice_bread',
              Category.bread,
              4,
              1,
              0,
              1,
              grain=1.5)
    food_item(rm, 'rye', 'tfc:food/rye', Category.grain, 4, 0, 0, 2)
    food_item(rm, 'rye_grain', 'tfc:food/rye_grain', Category.grain, 4, 0.5, 0,
              0.25)
    food_item(rm, 'rye_flour', 'tfc:food/rye_flour', Category.grain, 4, 0, 0,
              0.5)
    food_item(rm, 'rye_dough', 'tfc:food/rye_dough', Category.grain, 4, 0, 0,
              3)
    food_item(rm,
              'rye_bread',
              'tfc:food/rye_bread',
              Category.bread,
              4,
              1,
              0,
              1,
              grain=1.5)
    food_item(rm, 'wheat', 'tfc:food/wheat', Category.grain, 4, 0, 0, 2)
    food_item(rm, 'wheat_grain', 'tfc:food/wheat_grain', Category.grain, 4,
              0.5, 0, 0.25)
    food_item(rm, 'wheat_flour', 'tfc:food/wheat_flour', Category.grain, 4, 0,
              0, 0.5)
    food_item(rm, 'wheat_dough', 'tfc:food/wheat_dough', Category.grain, 4, 0,
              0, 3)
    food_item(rm,
              'wheat_bread',
              'tfc:food/wheat_bread',
              Category.bread,
              4,
              1,
              0,
              1,
              grain=1)
    food_item(rm,
              'beet',
              'tfc:food/beet',
              Category.vegetable,
              4,
              2,
              0,
              0.7,
              veg=1)
    food_item(rm,
              'cabbage',
              'tfc:food/cabbage',
              Category.vegetable,
              4,
              0.5,
              0,
              1.2,
              veg=1)
    food_item(rm,
              'carrot',
              'tfc:food/carrot',
              Category.vegetable,
              4,
              2,
              0,
              0.7,
              veg=1)
    food_item(rm,
              'garlic',
              'tfc:food/garlic',
              Category.vegetable,
              4,
              0.5,
              0,
              0.4,
              veg=2)
    food_item(rm,
              'green_bean',
              'tfc:food/green_bean',
              Category.vegetable,
              4,
              0.5,
              0,
              3.5,
              veg=1)
    food_item(rm,
              'green_bell_pepper',
              'tfc:food/green_bell_pepper',
              Category.vegetable,
              4,
              0.5,
              0,
              2.7,
              veg=1)
    food_item(rm,
              'onion',
              'tfc:food/onion',
              Category.vegetable,
              4,
              0.5,
              0,
              0.5,
              veg=1)
    food_item(rm,
              'potato',
              'tfc:food/potato',
              Category.vegetable,
              4,
              2,
              0,
              0.666,
              veg=1.5)
    food_item(rm,
              'red_bell_pepper',
              'tfc:food/red_bell_pepper',
              Category.vegetable,
              4,
              1,
              0,
              2.5,
              veg=1)
    food_item(rm,
              'dried_seaweed',
              'tfc:food/dried_seaweed',
              Category.vegetable,
              2,
              1,
              0,
              2.5,
              veg=0.5)
    food_item(rm,
              'dried_kelp',
              'tfc:food/dried_kelp',
              Category.vegetable,
              2,
              1,
              0,
              2.5,
              veg=0.5)
    food_item(rm,
              'cattail_root',
              'tfc:food/cattail_root',
              Category.vegetable,
              2,
              1,
              0,
              2.5,
              grain=0.5)
    food_item(rm,
              'soybean',
              'tfc:food/soybean',
              Category.vegetable,
              4,
              2,
              0,
              2.5,
              veg=0.5,
              protein=1)
    food_item(rm,
              'squash',
              'tfc:food/squash',
              Category.vegetable,
              4,
              1,
              0,
              1.67,
              veg=1.5)
    food_item(rm,
              'tomato',
              'tfc:food/tomato',
              Category.vegetable,
              4,
              0.5,
              5,
              3.5,
              veg=1.5)
    food_item(rm,
              'yellow_bell_pepper',
              'tfc:food/yellow_bell_pepper',
              Category.vegetable,
              4,
              1,
              0,
              2.5,
              veg=1)
    food_item(rm,
              'cheese',
              'tfc:food/cheese',
              Category.dairy,
              4,
              2,
              0,
              0.3,
              dairy=3)
    food_item(rm,
              'cooked_egg',
              'tfc:food/cooked_egg',
              Category.other,
              4,
              0.5,
              0,
              4,
              protein=0.75,
              dairy=0.25)
    # todo: figure out what to do with sugarcane, do we need a different plant? or item or something? or modify the vanilla one
    # food_item(rm, 'sugarcane', 'tfc:food/sugarcane', Category.grain, 4, 0, 0, 1.6, grain=0.5)
    food_item(rm,
              'beef',
              'tfc:food/beef',
              Category.meat,
              4,
              0,
              0,
              2,
              protein=2)
    food_item(rm,
              'pork',
              'tfc:food/pork',
              Category.meat,
              4,
              0,
              0,
              2,
              protein=1.5)
    food_item(rm,
              'chicken',
              'tfc:food/chicken',
              Category.meat,
              4,
              0,
              0,
              3,
              protein=1.5)
    food_item(rm,
              'mutton',
              'tfc:food/mutton',
              Category.meat,
              4,
              0,
              0,
              3,
              protein=1.5)
    food_item(rm,
              'bluegill',
              'tfc:food/bluegill',
              Category.meat,
              4,
              0,
              0,
              3,
              protein=1)
    food_item(rm, 'cod', 'tfc:food/cod', Category.meat, 4, 0, 0, 3, protein=1)
    food_item(rm,
              'salmon',
              'tfc:food/salmon',
              Category.meat,
              4,
              0,
              0,
              3,
              protein=1)
    food_item(rm,
              'tropical_fish',
              'tfc:food/tropical_fish',
              Category.meat,
              4,
              0,
              0,
              3,
              protein=1)
    food_item(rm,
              'bear',
              'tfc:food/bear',
              Category.meat,
              4,
              0,
              0,
              2,
              protein=1.5)
    # food_item(rm, 'calamari', 'tfc:food/calamari', Category.meat, 4, 0, 0, 3, protein=0.5)
    food_item(rm,
              'horse_meat',
              'tfc:food/horse_meat',
              Category.meat,
              4,
              0,
              0,
              2,
              protein=1.5)
    food_item(rm,
              'pheasant',
              'tfc:food/pheasant',
              Category.meat,
              4,
              0,
              0,
              3,
              protein=1.5)
    food_item(rm,
              'venison',
              'tfc:food/venison',
              Category.meat,
              4,
              0,
              0,
              2,
              protein=1)
    food_item(rm,
              'wolf',
              'tfc:food/wolf',
              Category.meat,
              4,
              0,
              0,
              3,
              protein=0.5)
    food_item(rm,
              'rabbit',
              'tfc:food/rabbit',
              Category.meat,
              4,
              0,
              0,
              3,
              protein=0.5)
    food_item(rm,
              'hyena',
              'tfc:food/hyena',
              Category.meat,
              4,
              0,
              0,
              3,
              protein=0.5)
    food_item(rm,
              'duck',
              'tfc:food/duck',
              Category.meat,
              4,
              0,
              0,
              3,
              protein=0.5)
    food_item(rm,
              'chevon',
              'tfc:food/chevon',
              Category.meat,
              4,
              0,
              0,
              3,
              protein=0.5)
    food_item(rm,
              'gran_feline',
              'tfc:food/gran_feline',
              Category.meat,
              4,
              0,
              0,
              3,
              protein=0.5)
    food_item(rm,
              'camelidae',
              'tfc:food/camelidae',
              Category.meat,
              4,
              0,
              0,
              3,
              protein=0.5)
    food_item(rm,
              'cooked_beef',
              'tfc:food/cooked_beef',
              Category.cooked_meat,
              4,
              2,
              0,
              1.5,
              protein=2.5)
    food_item(rm,
              'cooked_pork',
              'tfc:food/cooked_pork',
              Category.cooked_meat,
              4,
              2,
              0,
              1.5,
              protein=2.5)
    food_item(rm,
              'cooked_chicken',
              'tfc:food/cooked_chicken',
              Category.cooked_meat,
              4,
              2,
              0,
              2.25,
              protein=2.5)
    food_item(rm,
              'cooked_mutton',
              'tfc:food/cooked_mutton',
              Category.cooked_meat,
              4,
              2,
              0,
              2.25,
              protein=2.5)
    food_item(rm,
              'cooked_cod',
              'tfc:food/cooked_cod',
              Category.cooked_meat,
              4,
              1,
              0,
              2.25,
              protein=2)
    food_item(rm,
              'cooked_tropical_fish',
              'tfc:food/cooked_tropical_fish',
              Category.cooked_meat,
              4,
              1,
              0,
              1.5,
              protein=2)
    food_item(rm,
              'cooked_salmon',
              'tfc:food/cooked_salmon',
              Category.cooked_meat,
              4,
              1,
              0,
              2.25,
              protein=2)
    food_item(rm,
              'cooked_bluegill',
              'tfc:food/cooked_bluegill',
              Category.cooked_meat,
              4,
              1,
              0,
              2.25,
              protein=2)
    food_item(rm,
              'cooked_bear',
              'tfc:food/cooked_bear',
              Category.cooked_meat,
              4,
              1,
              0,
              1.5,
              protein=2.5)
    # food_item(rm, 'cooked_calamari', 'tfc:food/cooked_calamari', Category.cooked_meat, 4, 1, 0, 2.25, protein=1.5)
    food_item(rm,
              'cooked_horse_meat',
              'tfc:food/cooked_horse_meat',
              Category.cooked_meat,
              4,
              2,
              0,
              1.5,
              protein=2.5)
    food_item(rm,
              'cooked_pheasant',
              'tfc:food/cooked_pheasant',
              Category.cooked_meat,
              4,
              1,
              0,
              2.25,
              protein=2.5)
    food_item(rm,
              'cooked_venison',
              'tfc:food/cooked_venison',
              Category.cooked_meat,
              4,
              1,
              0,
              1.5,
              protein=2)
    food_item(rm,
              'cooked_wolf',
              'tfc:food/cooked_wolf',
              Category.cooked_meat,
              4,
              1,
              0,
              2.25,
              protein=1.5)
    food_item(rm,
              'cooked_rabbit',
              'tfc:food/cooked_rabbit',
              Category.cooked_meat,
              4,
              1,
              0,
              2.25,
              protein=1.5)
    food_item(rm,
              'cooked_hyena',
              'tfc:food/cooked_hyena',
              Category.cooked_meat,
              4,
              1,
              0,
              2.25,
              protein=1.5)
    food_item(rm,
              'cooked_duck',
              'tfc:food/cooked_duck',
              Category.cooked_meat,
              4,
              1,
              0,
              2.25,
              protein=1.5)
    food_item(rm,
              'cooked_chevon',
              'tfc:food/cooked_chevon',
              Category.cooked_meat,
              4,
              1,
              0,
              2.25,
              protein=2)
    food_item(rm,
              'cooked_gran_feline',
              'tfc:food/cooked_gran_feline',
              Category.cooked_meat,
              4,
              2,
              0,
              2.25,
              protein=2.5)
    food_item(rm,
              'cooked_camelidae',
              'tfc:food/cooked_camelidae',
              Category.cooked_meat,
              4,
              2,
              0,
              2.25,
              protein=2.5)

    # Drinkables

    drinkable(rm,
              'fresh_water', ['minecraft:water', 'tfc:river_water'],
              thirst=10)
    drinkable(rm, 'salt_water', 'tfc:salt_water', thirst=-1)

    # Climate Ranges

    for berry, data in BERRIES.items():
        climate_range(rm,
                      'plant/%s_bush' % berry,
                      hydration=(hydration_from_rainfall(data.min_rain), 100,
                                 0),
                      temperature=(data.min_temp, data.max_temp, 0))

    # Entities
    rm.data(('tfc', 'fauna', 'isopod'),
            fauna(distance_below_sea_level=20,
                  climate=climate_config(max_temp=14)))
    rm.data(('tfc', 'fauna', 'lobster'),
            fauna(distance_below_sea_level=20,
                  climate=climate_config(max_temp=21)))
    rm.data(('tfc', 'fauna', 'horseshoe_crab'),
            fauna(distance_below_sea_level=10,
                  climate=climate_config(min_temp=10,
                                         max_temp=21,
                                         max_rain=400)))
    rm.data(('tfc', 'fauna', 'cod'),
            fauna(climate=climate_config(max_temp=18),
                  distance_below_sea_level=5))
    rm.data(('tfc', 'fauna', 'pufferfish'),
            fauna(climate=climate_config(min_temp=10),
                  distance_below_sea_level=3))
    rm.data(('tfc', 'fauna', 'tropical_fish'),
            fauna(climate=climate_config(min_temp=18),
                  distance_below_sea_level=3))
    rm.data(('tfc', 'fauna', 'jellyfish'),
            fauna(climate=climate_config(min_temp=18),
                  distance_below_sea_level=3))
    # rm.data(('tfc', 'fauna', 'orca'), fauna(distance_below_sea_level=35, climate=climate_config(max_temp=19, min_rain=100), chance=10))
    # rm.data(('tfc', 'fauna', 'dolphin'), fauna(distance_below_sea_level=20, climate=climate_config(min_temp=10, min_rain=200), chance=10))
    # rm.data(('tfc', 'fauna', 'manatee'), fauna(distance_below_sea_level=3, climate=climate_config(min_temp=20, min_rain=300), chance=10))
    rm.data(('tfc', 'fauna', 'salmon'),
            fauna(climate=climate_config(min_temp=-5)))
    rm.data(('tfc', 'fauna', 'bluegill'),
            fauna(climate=climate_config(min_temp=-10, max_temp=26)))
    # rm.data(('tfc', 'fauna', 'penguin'), fauna(climate=climate_config(max_temp=-14, min_rain=75)))
    # rm.data(('tfc', 'fauna', 'turtle'), fauna(climate=climate_config(min_temp=21, min_rain=250)))

    rm.entity_loot('cod', 'tfc:food/cod')
    rm.entity_loot('bluegill', 'tfc:food/bluegill')
    rm.entity_loot('tropical_fish', 'tfc:food/tropical_fish')
    rm.entity_loot('salmon', 'tfc:food/salmon')
    rm.entity_loot('pufferfish', 'minecraft:pufferfish')
Esempio n. 2
0
def generate(rm: ResourceManager):
    # Rock block variants
    for rock in ROCKS.keys():
        for block_type in ROCK_BLOCK_TYPES:
            if block_type == 'spike':
                # Spikes have special block states
                block = rm.blockstate(
                    ('rock', block_type, rock),
                    variants=dict(('part=%s' % part, {
                        'model':
                        'tfc:block/rock/%s/%s_%s' % (block_type, rock, part)
                    }) for part in ROCK_SPIKE_PARTS))
                block.with_lang(lang('%s spike', rock))
                block.with_block_loot({
                    'entries':
                    'tfc:rock/loose/%s' % rock,
                    'functions': [loot_tables.set_count(1, 2)]
                })
                # Individual models
                rm.item_model(('rock', block_type, rock),
                              'tfc:block/rock/raw/%s' % rock,
                              parent='tfc:block/rock/spike/%s_base' % rock)
                for part in ROCK_SPIKE_PARTS:
                    rm.block_model(
                        ('rock', block_type, '%s_%s' % (rock, part)), {
                            'texture': 'tfc:block/rock/raw/%s' % rock,
                            'particle': 'tfc:block/rock/raw/%s' % rock
                        },
                        parent='tfc:block/rock/spike_%s' % part)

            elif block_type == 'loose':
                # One block state and multiple models for the block
                block = rm.blockstate(
                    'rock/loose/%s' % rock,
                    variants={
                        'count=1': [{
                            'model': 'tfc:block/rock/pebble/%s' % rock,
                            'y': 90
                        }, {
                            'model': 'tfc:block/rock/pebble/%s' % rock
                        }, {
                            'model': 'tfc:block/rock/pebble/%s' % rock,
                            'y': 180
                        }, {
                            'model': 'tfc:block/rock/pebble/%s' % rock,
                            'y': 270
                        }],
                        'count=2': [{
                            'model': 'tfc:block/rock/rubble/%s' % rock,
                            'y': 90
                        }, {
                            'model': 'tfc:block/rock/rubble/%s' % rock
                        }, {
                            'model': 'tfc:block/rock/rubble/%s' % rock,
                            'y': 180
                        }, {
                            'model': 'tfc:block/rock/rubble/%s' % rock,
                            'y': 270
                        }],
                        'count=3': [{
                            'model': 'tfc:block/rock/boulder/%s' % rock,
                            'y': 90
                        }, {
                            'model': 'tfc:block/rock/boulder/%s' % rock
                        }, {
                            'model': 'tfc:block/rock/boulder/%s' % rock,
                            'y': 180
                        }, {
                            'model': 'tfc:block/rock/boulder/%s' % rock,
                            'y': 270
                        }]
                    },
                    use_default_model=False)
                for loose_type in ('pebble', 'rubble', 'boulder'):
                    rm.block_model('tfc:rock/%s/%s' % (loose_type, rock),
                                   'tfc:item/loose_rock/%s' % rock,
                                   parent='tfc:block/groundcover/%s' %
                                   loose_type)

                block.with_lang(lang('%s %s', rock, block_type))
                block.with_tag('can_be_snow_piled')
                block.with_block_loot({
                    'entries': [{
                        'name':
                        'tfc:rock/loose/%s' % rock,
                        'functions': [{
                            **loot_tables.set_count(2), 'conditions': [
                                block_state_property(
                                    'tfc:rock/loose/%s' % rock, {'count': '2'})
                            ]
                        }, {
                            **loot_tables.set_count(3), 'conditions': [
                                block_state_property(
                                    'tfc:rock/loose/%s' % rock, {'count': '3'})
                            ]
                        },
                                      explosion_decay()]
                    }]
                })

                # Model for the item
                rm.item_model(('rock', 'loose', rock),
                              'tfc:item/loose_rock/%s' % rock)

            else:
                block = rm.blockstate(('rock', block_type, rock))
                if block_type == 'hardened':
                    block.with_block_model('tfc:block/rock/raw/%s' %
                                           rock)  # Hardened uses the raw model
                else:
                    block.with_block_model('tfc:block/rock/%s/%s' %
                                           (block_type, rock))
                block.with_item_model()

                if block_type in CUTTABLE_ROCKS:
                    # Stairs
                    rm.block('tfc:rock/' + block_type + '/' +
                             rock).make_stairs()
                    rm.block_loot(
                        'tfc:rock/' + block_type + '/' + rock + '_stairs',
                        'tfc:rock/' + block_type + '/' + rock + '_stairs')
                    rm.lang(
                        'block.tfc.rock.' + block_type + '.' + rock +
                        '_stairs', lang('%s %s Stairs', rock, block_type))
                    # Slabs
                    rm.block('tfc:rock/' + block_type + '/' + rock).make_slab()
                    slab_namespace = 'tfc:rock/' + block_type + '/' + rock + '_slab'
                    rm.block_loot(
                        slab_namespace, {
                            'entries': [{
                                'functions': [{
                                    **loot_tables.set_count(2), 'conditions': [
                                        block_state_property(
                                            slab_namespace, {'type': 'double'})
                                    ]
                                },
                                              explosion_decay()],
                                'name':
                                slab_namespace
                            }]
                        })
                    rm.lang(
                        'block.tfc.rock.' + block_type + '.' + rock + '_slab',
                        lang('%s %s Slab', rock, block_type))
                    # Walls
                    rm.block('tfc:rock/' + block_type + '/' + rock).make_wall()
                    rm.block_loot(
                        'tfc:rock/' + block_type + '/' + rock + '_wall',
                        'tfc:rock/' + block_type + '/' + rock + '_wall')
                    rm.lang(
                        'block.tfc.rock.' + block_type + '.' + rock + '_wall',
                        lang('%s %s Wall', rock, block_type))
                    rm.block_tag(
                        'minecraft:walls',
                        'tfc:rock/' + block_type + '/' + rock + '_wall')
                # Loot
                if block_type == 'raw':
                    block.with_block_loot(
                        alternatives([{
                            'name': 'tfc:rock/raw/%s' % rock,
                            'conditions': ['tfc:is_isolated'],
                        }, {
                            'name':
                            'tfc:rock/loose/%s' % rock,
                            'functions': [loot_tables.set_count(1, 4)]
                        }]))
                elif block_type == 'hardened':
                    block.with_block_loot({
                        'entries':
                        'tfc:rock/loose/%s' % rock,
                        'functions': [loot_tables.set_count(1, 4)]
                    })
                else:
                    block.with_block_loot('tfc:rock/%s/%s' %
                                          (block_type, rock))
                # Lang
                if block_type in {'smooth', 'raw', 'chiseled', 'hardened'}:
                    block.with_lang(lang('%s %s', block_type, rock))
                else:
                    block.with_lang(lang('%s %s', rock, block_type))

        # Ores
        for ore, ore_data in ORES.items():
            if ore_data.graded:
                # Small Ores / Groundcover Blocks
                block = rm.blockstate('tfc:ore/small_%s' % ore,
                                      variants={
                                          "": [{
                                              'model':
                                              'tfc:block/groundcover/%s' % ore,
                                              'y':
                                              90
                                          }, {
                                              'model':
                                              'tfc:block/groundcover/%s' % ore
                                          }, {
                                              'model':
                                              'tfc:block/groundcover/%s' % ore,
                                              'y':
                                              180
                                          }, {
                                              'model':
                                              'tfc:block/groundcover/%s' % ore,
                                              'y':
                                              270
                                          }]
                                      },
                                      use_default_model=False)
                block.with_lang(lang('small %s', ore))
                block.with_block_loot('tfc:ore/small_%s' % ore)
                block.with_tag('can_be_snow_piled')

                rm.item_model('tfc:ore/small_%s' % ore).with_lang(
                    lang('small %s', ore))

                for grade in ORE_GRADES.keys():
                    block = rm.blockstate(
                        ('ore', grade + '_' + ore, rock),
                        'tfc:block/ore/%s_%s/%s' % (grade, ore, rock))
                    block.with_block_model(
                        {
                            'all': 'tfc:block/rock/raw/%s' % rock,
                            'particle': 'tfc:block/rock/raw/%s' % rock,
                            'overlay': 'tfc:block/ore/%s_%s' % (grade, ore)
                        },
                        parent='tfc:block/ore')
                    block.with_item_model()
                    block.with_lang(lang('%s %s %s', grade, rock, ore))
                    block.with_block_loot('tfc:ore/%s_%s' % (grade, ore))
            else:
                block = rm.blockstate(('ore', ore, rock),
                                      'tfc:block/ore/%s/%s' % (ore, rock))
                block.with_block_model(
                    {
                        'all': 'tfc:block/rock/raw/%s' % rock,
                        'particle': 'tfc:block/rock/raw/%s' % rock,
                        'overlay': 'tfc:block/ore/%s' % ore
                    },
                    parent='tfc:block/ore')
                block.with_item_model()
                block.with_lang(lang('%s %s', rock, ore))
                rm.block_loot('tfc:ore/%s/%s' % (ore, rock),
                              'tfc:ore/%s' % ore)

    # Loose Ore Items
    for ore, ore_data in ORES.items():
        if ore_data.graded:
            for grade in ORE_GRADES.keys():
                rm.item_model('tfc:ore/%s_%s' % (grade, ore)).with_lang(
                    lang('%s %s', grade, ore))
            rm.item_model('tfc:ore/small_%s' % ore).with_lang(
                lang('small %s', ore))
        else:
            rm.item_model('tfc:ore/%s' % ore).with_lang(lang('%s', ore))

    # Sand
    for sand in SAND_BLOCK_TYPES:
        block = rm.blockstate(('sand', sand))
        block.with_block_model('tfc:block/sand/%s' % sand)
        block.with_item_model()
        block.with_block_loot('tfc:sand/%s' % sand)
        block.with_lang(lang('%s Sand', sand))

        # Sandstone
        raw = 'tfc:block/sandstone/bottom/%s' % sand  # vanilla sandstone bottom
        top = 'tfc:block/sandstone/top/%s' % sand  # vanilla sandstone top
        cut = 'tfc:block/sandstone/cut/%s' % sand  # vanilla sandstone side

        for variant in ('raw', 'cut', 'smooth'):
            block = rm.blockstate(('%s_sandstone' % variant, sand))
            if variant == 'raw':
                block.with_block_model(raw)
                block.make_slab(bottom_texture=raw,
                                side_texture=raw,
                                top_texture=raw)
                block.make_stairs(bottom_texture=raw,
                                  side_texture=raw,
                                  top_texture=raw)
                block.make_wall(texture=raw)
            elif variant == 'smooth':
                block.with_block_model(top)
                block.make_slab(bottom_texture=top,
                                side_texture=top,
                                top_texture=top)
                block.make_stairs(bottom_texture=top,
                                  side_texture=top,
                                  top_texture=top)
                block.make_wall(texture=top)
            else:
                block.with_block_model({
                    'end': top,
                    'side': cut
                },
                                       parent='minecraft:block/cube_column')
                block.make_slab(bottom_texture=top,
                                side_texture=cut,
                                top_texture=top)
                block.make_stairs(bottom_texture=top,
                                  side_texture=cut,
                                  top_texture=top)
                block.make_wall(texture=cut)
            block.with_item_model()
            rm.block_tag('minecraft:walls',
                         'tfc:%s_sandstone/%s_wall' % (variant, sand))

            for extra in ('', ' slab', ' stairs', ' wall'):
                rm.block(('%s_sandstone' % variant, sand + extra)).with_lang(
                    lang('%s %s sandstone' + extra, variant, sand))

    # Groundcover
    for misc in MISC_GROUNDCOVER:
        block = rm.blockstate(
            ('groundcover', misc),
            variants={
                "": [{
                    'model': 'tfc:block/groundcover/%s' % misc,
                    'y': 90
                }, {
                    'model': 'tfc:block/groundcover/%s' % misc
                }, {
                    'model': 'tfc:block/groundcover/%s' % misc,
                    'y': 180
                }, {
                    'model': 'tfc:block/groundcover/%s' % misc,
                    'y': 270
                }]
            },
            use_default_model=False)
        block.with_lang(lang(misc))
        block.with_tag('can_be_snow_piled')

        if misc in {'stick', 'flint', 'feather', 'rotten_flesh',
                    'bone'}:  # Vanilla ground cover
            block.with_block_loot('minecraft:%s' % misc)
        else:
            block.with_block_loot('tfc:groundcover/%s' % misc)
            rm.item_model(('groundcover', misc),
                          'tfc:item/groundcover/%s' % misc)

    # Peat
    block = rm.blockstate('peat')
    block.with_block_model('tfc:block/peat')
    block.with_item_model()
    block.with_block_loot('tfc:peat')
    block.with_lang(lang('Peat'))

    rm.blockstate('thatch').with_block_model().with_item_model(
    ).with_block_loot('tfc:thatch').with_lang(lang('Thatch'))

    block = rm.block_model('thatch_bed').with_item_model().with_lang(
        lang('Thatch Bed'))
    block.with_block_loot({
        'entries': [{
            'type': 'minecraft:item',
            'name': 'tfc:thatch_bed'
        }],
        'conditions': [
            'minecraft:survives_explosion',
            block_state_property('tfc:thatch_bed', {'part': 'head'})
        ]
    })

    # Dirt
    for soil in SOIL_BLOCK_VARIANTS:
        # Regular Dirt
        block = rm.blockstate(
            ('dirt', soil),
            variants={
                '': [{
                    'model': 'tfc:block/dirt/%s' % soil,
                    'y': i
                } for i in range(0, 360, 90)]
            },
            use_default_model=False)
        block.with_block_model()
        block.with_item_model()
        block.with_block_loot('tfc:dirt/%s' % soil)
        block.with_lang(lang('%s Dirt', soil))

        # Clay Dirt
        block = rm.blockstate(
            ('clay', soil),
            variants={
                '': [{
                    'model': 'tfc:block/clay/%s' % soil,
                    'y': i
                } for i in range(0, 360, 90)]
            },
            use_default_model=False)
        block.with_block_model()
        block.with_block_loot({
            'entries': [{
                'name': 'minecraft:clay_ball',
                'functions': [loot_tables.set_count(1, 3)]
            }]
        })
        block.with_lang(lang('%s Clay Dirt', soil))
        block.with_item_model()

    # Grass
    north_face = {
        'from': [0, 0, 0],
        'to': [16, 16, 0],
        'faces': {
            'north': {
                'texture': '#texture',
                'cullface': 'north'
            }
        }
    }
    north_face_overlay = {
        'from': [0, 0, 0],
        'to': [16, 16, 0],
        'faces': {
            'north': {
                'texture': '#overlay',
                'cullface': 'north'
            }
        }
    }
    north_face_overlay_tint0 = {
        'from': [0, 0, 0],
        'to': [16, 16, 0],
        'faces': {
            'north': {
                'texture': '#overlay',
                'cullface': 'north',
                'tintindex': 0
            }
        }
    }

    rm.block_model('grass_top',
                   textures={
                       'overlay': 'tfc:block/grass_top',
                       'particle': '#texture'
                   },
                   parent='block/block',
                   elements=[north_face_overlay_tint0])
    rm.block_model('grass_snowy_top',
                   textures={
                       'overlay': 'minecraft:block/snow',
                       'particle': '#texture'
                   },
                   parent='block/block',
                   elements=[north_face_overlay])
    rm.block_model('grass_side',
                   textures={
                       'overlay': 'tfc:block/grass_side',
                       'particle': '#texture'
                   },
                   parent='block/block',
                   elements=[north_face, north_face_overlay_tint0])
    rm.block_model('grass_snowy_side',
                   textures={
                       'overlay': 'tfc:block/grass_snowy_side',
                       'particle': '#texture'
                   },
                   parent='block/block',
                   elements=[north_face, north_face_overlay])
    rm.block_model('grass_bottom',
                   textures={
                       'texture': '#texture',
                       'particle': '#texture'
                   },
                   parent='block/block',
                   elements=[north_face])

    # Grass (Peat, Normal + Clay) - Helper Functions
    def grass_multipart(model: str):
        return [{
            'model': model + '/bottom',
            'x': 90
        }, ({
            'snowy': False
        }, {
            'model': model + '/top',
            'x': 270
        }), ({
            'snowy': True
        }, {
            'model': model + '/snowy_top',
            'x': 270
        }), ({
            'north': True,
            'snowy': False
        }, {
            'model': model + '/top'
        }), ({
            'east': True,
            'snowy': False
        }, {
            'model': model + '/top',
            'y': 90
        }),
                ({
                    'south': True,
                    'snowy': False
                }, {
                    'model': model + '/top',
                    'y': 180
                }),
                ({
                    'west': True,
                    'snowy': False
                }, {
                    'model': model + '/top',
                    'y': 270
                }),
                ({
                    'north': True,
                    'snowy': True
                }, {
                    'model': model + '/snowy_top'
                }),
                ({
                    'east': True,
                    'snowy': True
                }, {
                    'model': model + '/snowy_top',
                    'y': 90
                }),
                ({
                    'south': True,
                    'snowy': True
                }, {
                    'model': model + '/snowy_top',
                    'y': 180
                }),
                ({
                    'west': True,
                    'snowy': True
                }, {
                    'model': model + '/snowy_top',
                    'y': 270
                }),
                ({
                    'north': False,
                    'snowy': False
                }, {
                    'model': model + '/side'
                }),
                ({
                    'east': False,
                    'snowy': False
                }, {
                    'model': model + '/side',
                    'y': 90
                }),
                ({
                    'south': False,
                    'snowy': False
                }, {
                    'model': model + '/side',
                    'y': 180
                }),
                ({
                    'west': False,
                    'snowy': False
                }, {
                    'model': model + '/side',
                    'y': 270
                }),
                ({
                    'north': False,
                    'snowy': True
                }, {
                    'model': model + '/snowy_side'
                }),
                ({
                    'east': False,
                    'snowy': True
                }, {
                    'model': model + '/snowy_side',
                    'y': 90
                }),
                ({
                    'south': False,
                    'snowy': True
                }, {
                    'model': model + '/snowy_side',
                    'y': 180
                }),
                ({
                    'west': False,
                    'snowy': True
                }, {
                    'model': model + '/snowy_side',
                    'y': 270
                })]

    def grass_models(name: utils.ResourceIdentifier, texture: str):
        rm.block_model((name, 'top'), {'texture': texture},
                       parent='tfc:block/grass_top')
        rm.block_model((name, 'snowy_top'), {'texture': texture},
                       parent='tfc:block/grass_snowy_top')
        rm.block_model((name, 'side'), {'texture': texture},
                       parent='tfc:block/grass_side')
        rm.block_model((name, 'snowy_side'), {'texture': texture},
                       parent='tfc:block/grass_snowy_side')
        rm.block_model((name, 'bottom'), {'texture': texture},
                       parent='tfc:block/grass_bottom')

    # Peat Grass
    block = rm.blockstate_multipart('peat_grass',
                                    grass_multipart('tfc:block/peat_grass'))
    block.with_block_loot('tfc:peat')
    block.with_tag('grass')
    block.with_lang(lang('Peat Grass'))
    grass_models('peat_grass', 'tfc:block/peat')

    # Grass Blocks
    for soil in SOIL_BLOCK_VARIANTS:
        for grass_var, dirt in (('grass', 'tfc:block/dirt/%s' % soil),
                                ('clay_grass', 'tfc:block/clay/%s' % soil)):
            block = rm.blockstate_multipart(
                (grass_var, soil),
                grass_multipart('tfc:block/%s/%s' % (grass_var, soil)))
            block.with_block_loot('tfc:dirt/%s' % soil)
            block.with_tag('grass')
            block.with_lang(lang('%s %s', soil, grass_var))
            grass_models((grass_var, soil), dirt)

        # Farmland
        block = rm.blockstate(('farmland', soil))
        block.with_block_model(
            {
                'dirt': 'tfc:block/dirt/%s' % soil,
                'top': 'tfc:block/farmland/%s' % soil
            },
            parent='block/template_farmland')
        block.with_item_model()
        block.with_block_loot('tfc:dirt/%s' % soil)
        block.with_tag('farmland')
        block.with_lang(lang('%s farmland', soil))

    # Snow Piles
    block = rm.blockstate(
        'snow_pile',
        variants=dict((('layers=%d' % i), {
            'model':
            'minecraft:block/snow_height%d' %
            (i * 2) if i != 8 else 'minecraft:block/snow_block'
        }) for i in range(1, 1 + 8)))
    block.with_lang(lang('Snow Pile'))
    rm.item_model('snow_pile',
                  parent='minecraft:block/snow_height2',
                  no_textures=True)

    # Loot table for snow blocks and snow piles - override the vanilla one to only return one snowball per layer
    def snow_block_loot_table(block: str):
        rm.block_loot(
            block, {
                'entries': [{
                    'type':
                    'minecraft:alternatives',
                    'children':
                    utils.loot_entry_list([{
                        'conditions': [silk_touch()],
                        'name': 'minecraft:snow'
                    }, 'minecraft:snowball'])
                }],
                'conditions': [{
                    'condition': 'minecraft:entity_properties',
                    'predicate': {},
                    'entity': 'this'
                }]
            })

    snow_block_loot_table('snow_pile')
    snow_block_loot_table('minecraft:snow')

    # Sea Ice
    block = rm.blockstate(
        'sea_ice').with_block_model().with_item_model().with_lang(
            lang('sea ice'))
    block.with_block_loot({
        'entries': 'minecraft:ice',
        'conditions': [silk_touch()]
    })

    # Hides
    for size in ('small', 'medium', 'large'):
        for hide in ('prepared', 'raw', 'scraped', 'sheepskin', 'soaked'):
            item = rm.item_model('%s_%s_hide' % (size, hide),
                                 'tfc:item/hide/%s/%s' % (size, hide))
            if item != 'sheepskin':
                item.with_lang(lang('%s %s hide', size, hide))
            else:
                item.with_lang(lang('%s %s', size, hide))

    # Rock Tools
    for rock in ROCK_CATEGORIES:
        for rock_item in ROCK_ITEMS:
            item = rm.item_model(('stone', rock_item, rock),
                                 'tfc:item/stone/%s' % rock_item,
                                 parent='item/handheld')
            item.with_lang(lang('stone %s', rock_item))

    # Rock Items
    for rock in ROCKS.keys():
        rm.item_model(
            ('brick', rock),
            'tfc:item/brick/%s' % rock).with_lang(lang('%s brick', rock))

    for metal, metal_data in METALS.items():
        # Metal Items
        for metal_item, metal_item_data in METAL_ITEMS.items():
            if metal_item_data.type in metal_data.types or metal_item_data.type == 'all':
                item = rm.item_model(
                    ('metal', '%s' % metal_item, '%s' % metal),
                    'tfc:item/metal/%s/%s' % (metal_item, metal),
                    parent=metal_item_data.parent_model)
                item.with_lang(lang('%s %s' % (metal, metal_item)))

        # Metal Blocks
        for metal_block, metal_block_data in METAL_BLOCKS.items():
            if metal_block_data.type in metal_data.types or metal_block_data.type == 'all':
                block = rm.blockstate(('metal', '%s' % metal_block, metal))
                block.with_block_model(
                    {
                        'all': 'tfc:block/metal/%s' % metal,
                        'particle': 'tfc:block/metal/%s' % metal
                    },
                    parent=metal_block_data.parent_model)
                block.with_block_loot('tfc:metal/%s/%s' % (metal_block, metal))
                block.with_lang(lang('%s %s' % (metal, metal_block)))
                block.with_item_model()

    # Gems
    for gem in GEMS:
        rm.item_model(('gem', gem)).with_lang(lang('cut %s', gem))
        rm.item_model(('powder', gem)).with_lang(lang('%s powder', gem))

    # Plants
    for plant, plant_data in PLANTS.items():
        rm.lang('block.tfc.plant.%s' % plant, lang(plant))
    for plant in MISC_PLANT_FEATURES:
        rm.lang('block.tfc.plant.%s' % plant, lang(plant))
    for plant in ('tree_fern', 'arundo', 'winged_kelp', 'leafy_kelp',
                  'giant_kelp_flower'):
        rm.lang('block.tfc.plant.%s' % plant, lang(plant))
    rm.lang('block.tfc.sea_pickle', lang('sea_pickle'))

    # Wood Blocks
    for wood in WOODS:
        # Logs
        for variant in ('log', 'stripped_log', 'wood', 'stripped_wood'):
            block = rm.blockstate(
                ('wood', variant, wood),
                variants={
                    'axis=y': {
                        'model': 'tfc:block/wood/%s/%s' % (variant, wood)
                    },
                    'axis=z': {
                        'model': 'tfc:block/wood/%s/%s' % (variant, wood),
                        'x': 90
                    },
                    'axis=x': {
                        'model': 'tfc:block/wood/%s/%s' % (variant, wood),
                        'x': 90,
                        'y': 90
                    }
                },
                use_default_model=False)
            block.with_item_model()
            end = 'tfc:block/wood/%s/%s' % (variant.replace(
                'log', 'log_top').replace('wood', 'log'), wood)
            side = 'tfc:block/wood/%s/%s' % (variant.replace('wood',
                                                             'log'), wood)
            block.with_block_model({
                'end': end,
                'side': side
            },
                                   parent='block/cube_column')
            if 'stripped' in variant:
                block.with_lang(lang(variant.replace('_', ' ' + wood + ' ')))
            else:
                block.with_lang(lang('%s %s', wood, variant))
            if variant == 'log':
                block.with_tag('minecraft:logs')

        # Groundcover
        for variant in ('twig', 'fallen_leaves'):
            block = rm.blockstate(
                'wood/%s/%s' % (variant, wood),
                variants={
                    "": [{
                        'model': 'tfc:block/wood/%s/%s' % (variant, wood),
                        'y': 90
                    }, {
                        'model': 'tfc:block/wood/%s/%s' % (variant, wood)
                    }, {
                        'model': 'tfc:block/wood/%s/%s' % (variant, wood),
                        'y': 180
                    }, {
                        'model': 'tfc:block/wood/%s/%s' % (variant, wood),
                        'y': 270
                    }]
                },
                use_default_model=False)
            block.with_item_model()
            block.with_lang(lang('%s %s', wood, variant))

            if variant == 'twig':
                block.with_block_model(
                    {
                        'side': 'tfc:block/wood/log/%s' % wood,
                        'top': 'tfc:block/wood/log_top/%s' % wood
                    },
                    parent='tfc:block/groundcover/%s' % variant)
                block.with_block_loot('tfc:wood/twig/%s' % wood)
            elif variant == 'fallen_leaves':
                block.with_block_model('tfc:block/wood/leaves/%s' % wood,
                                       parent='tfc:block/groundcover/%s' %
                                       variant)
                block.with_block_loot('tfc:wood/%s/%s' % (variant, wood))

            block.with_tag('can_be_snow_piled')

        # Leaves
        block = rm.blockstate(('wood', 'leaves', wood),
                              model='tfc:block/wood/leaves/%s' % wood)
        block.with_block_model('tfc:block/wood/leaves/%s' % wood,
                               parent='block/leaves')
        block.with_item_model()
        block.with_tag('minecraft:leaves')

        # Sapling
        block = rm.blockstate(('wood', 'sapling', wood),
                              'tfc:block/wood/sapling/%s' % wood)
        block.with_block_model({'cross': 'tfc:block/wood/sapling/%s' % wood},
                               'block/cross')
        rm.item_model(('wood', 'sapling', wood),
                      'tfc:block/wood/sapling/%s' % wood)

        # Planks and variant blocks
        block = rm.block(('wood', 'planks', wood))
        block.with_blockstate()
        block.with_block_model()
        block.with_item_model()
        block.with_block_loot('tfc:wood/planks/%s' % wood)
        block.with_lang(lang('%s planks', wood))
        block.make_slab()
        block.make_stairs()
        block.make_button()
        block.make_door()
        block.make_pressure_plate()
        block.make_trapdoor()
        block.make_fence()
        block.make_fence_gate()

        # Tool Rack
        rack_namespace = 'tfc:wood/planks/%s_tool_rack' % wood
        rm.blockstate(rack_namespace,
                      model='tfc:block/wood/planks/%s_tool_rack' % wood,
                      variants={
                          'facing=east': {
                              'model':
                              'tfc:block/wood/planks/%s_tool_rack' % wood,
                              'y': 270
                          },
                          'facing=north': {
                              'model':
                              'tfc:block/wood/planks/%s_tool_rack' % wood,
                              'y': 180
                          },
                          'facing=south': {
                              'model':
                              'tfc:block/wood/planks/%s_tool_rack' % wood
                          },
                          'facing=west': {
                              'model':
                              'tfc:block/wood/planks/%s_tool_rack' % wood,
                              'y': 90
                          }
                      })
        rm.block_model(rack_namespace,
                       textures={'texture': 'tfc:block/wood/planks/%s' % wood},
                       parent='tfc:block/tool_rack')
        rm.item_model(rack_namespace,
                      parent='tfc:block/wood/planks/%s_tool_rack' % wood,
                      no_textures=True)
        rm.lang('block.tfc.wood.planks.%s_tool_rack' % wood,
                lang('%s Tool Rack', wood))
        rm.block_loot(rack_namespace, rack_namespace)

        # Bookshelf
        block = rm.blockstate('tfc:wood/planks/%s_bookshelf' % wood)
        block.with_block_model(
            {
                'end': 'tfc:block/wood/planks/%s' % wood,
                'side': 'tfc:block/wood/planks/%s_bookshelf' % wood
            },
            parent='minecraft:block/bookshelf')
        block.with_item_model()
        block.with_lang(lang('%s Bookshelf', wood))

        # Workbench
        rm.blockstate(
            ('wood', 'planks', '%s_workbench' % wood)).with_block_model(
                parent='minecraft:block/cube',
                textures={
                    'particle':
                    'tfc:block/wood/planks/%s_workbench_front' % wood,
                    'north': 'tfc:block/wood/planks/%s_workbench_front' % wood,
                    'south': 'tfc:block/wood/planks/%s_workbench_side' % wood,
                    'east': 'tfc:block/wood/planks/%s_workbench_side' % wood,
                    'west': 'tfc:block/wood/planks/%s_workbench_front' % wood,
                    'up': 'tfc:block/wood/planks/%s_workbench_top' % wood,
                    'down': 'tfc:block/wood/planks/%s' % wood
                }).with_item_model().with_lang(lang(
                    '%s Workbench', wood)).with_tag('tfc:workbench')

        # Doors
        rm.item_model('tfc:wood/planks/%s_door' % wood,
                      'tfc:item/wood/planks/%s_door' % wood)

        # Log Fences
        log_fence_namespace = 'tfc:wood/planks/' + wood + '_log_fence'
        rm.blockstate_multipart(
            log_fence_namespace,
            parts=block_states.fence_multipart(
                'tfc:block/wood/planks/' + wood + '_log_fence_post',
                'tfc:block/wood/planks/' + wood + '_log_fence_side'))
        rm.block_model(log_fence_namespace + '_post',
                       textures={'texture': 'tfc:block/wood/log/' + wood},
                       parent='block/fence_post')
        rm.block_model(log_fence_namespace + '_side',
                       textures={'texture': 'tfc:block/wood/planks/' + wood},
                       parent='block/fence_side')
        rm.block_model(log_fence_namespace + '_inventory',
                       textures={
                           'log': 'tfc:block/wood/log/' + wood,
                           'planks': 'tfc:block/wood/planks/' + wood
                       },
                       parent='tfc:block/log_fence_inventory')
        rm.item_model('tfc:wood/planks/' + wood + '_log_fence',
                      parent='tfc:block/wood/planks/' + wood +
                      '_log_fence_inventory',
                      no_textures=True)
        rm.block_loot(log_fence_namespace, log_fence_namespace)

        texture = 'tfc:block/wood/sheet/%s' % wood
        connection = 'tfc:block/wood/support/%s_connection' % wood
        rm.blockstate_multipart(('wood', 'vertical_support', wood), [
            {
                'model': 'tfc:block/wood/support/%s_vertical' % wood
            },
            ({
                'north': True
            }, {
                'model': connection,
                'y': 270
            }),
            ({
                'east': True
            }, {
                'model': connection
            }),
            ({
                'south': True
            }, {
                'model': connection,
                'y': 90
            }),
            ({
                'west': True
            }, {
                'model': connection,
                'y': 180
            }),
        ]).with_tag('tfc:support_beam').with_lang(lang(
            '%s Support', wood)).with_block_loot('tfc:wood/support/' + wood)
        rm.blockstate_multipart(('wood', 'horizontal_support', wood), [
            {
                'model': 'tfc:block/wood/support/%s_horizontal' % wood
            },
            ({
                'north': True
            }, {
                'model': connection,
                'y': 270
            }),
            ({
                'east': True
            }, {
                'model': connection
            }),
            ({
                'south': True
            }, {
                'model': connection,
                'y': 90
            }),
            ({
                'west': True
            }, {
                'model': connection,
                'y': 180
            }),
        ]).with_tag('tfc:support_beam').with_lang(lang(
            '%s Support', wood)).with_block_loot('tfc:wood/support/' + wood)

        rm.block_model('tfc:wood/support/%s_inventory' % wood,
                       textures={'texture': texture},
                       parent='tfc:block/wood/support/inventory')
        rm.block_model('tfc:wood/support/%s_vertical' % wood,
                       textures={
                           'texture': texture,
                           'particle': texture
                       },
                       parent='tfc:block/wood/support/vertical')
        rm.block_model('tfc:wood/support/%s_connection' % wood,
                       textures={
                           'texture': texture,
                           'particle': texture
                       },
                       parent='tfc:block/wood/support/connection')
        rm.block_model('tfc:wood/support/%s_horizontal' % wood,
                       textures={
                           'texture': texture,
                           'particle': texture
                       },
                       parent='tfc:block/wood/support/horizontal')
        rm.item_model(
            ('wood', 'support', wood),
            no_textures=True,
            parent='tfc:block/wood/support/%s_inventory' % wood).with_lang(
                lang('%s Support', wood))

        # Tags
        for fence_namespace in ('tfc:wood/planks/' + wood + '_fence',
                                log_fence_namespace):
            rm.block_tag('minecraft:wooden_fences', fence_namespace)
            rm.block_tag('minecraft:fences', fence_namespace)
            rm.block_tag('forge:fences', fence_namespace)
            rm.block_tag('forge:fences/wooden', fence_namespace)
        fence_gate_namespace = 'tfc:wood/planks/' + wood + '_fence_gate'
        rm.block_tag('forge:fence_gates/wooden', fence_gate_namespace)
        rm.block_tag('forge:fence_gates', fence_gate_namespace)
        rm.block_tag('minecraft:doors', 'tfc:wood/planks/' + wood + '_door')
        rm.block_tag('minecraft:buttons',
                     'tfc:wood/planks/' + wood + '_button')
        rm.block_tag('minecraft:wooden_buttons',
                     'tfc:wood/planks/' + wood + '_button')
        rm.block_tag('minecraft:wooden_pressure_plates',
                     'tfc:wood/planks/' + wood + '_pressure_plate')
        rm.block_tag('minecraft:wooden_slabs',
                     'tfc:wood/planks/' + wood + '_slab')
        rm.block_tag('minecraft:wooden_stairs',
                     'tfc:wood/planks/' + wood + '_stairs')
        for variant in ('log', 'stripped_log', 'wood', 'stripped_wood'):
            if variant != 'log':
                rm.block_tag('minecraft:logs',
                             'tfc:wood/' + variant + '/' + wood)
            rm.block_tag('tfc:' + wood + '_logs',
                         'tfc:wood/' + variant + '/' + wood)
            rm.block_tag('tfc:creeping_plantable_on',
                         'tfc:wood/' + variant + '/' + wood)

        # Lang
        for variant in ('door', 'trapdoor', 'fence', 'log_fence', 'fence_gate',
                        'button', 'pressure_plate', 'slab', 'stairs'):
            rm.lang('block.tfc.wood.planks.' + wood + '_' + variant,
                    lang('%s %s', wood, variant))
        for variant in ('sapling', 'leaves'):
            rm.lang('block.tfc.wood.' + variant + '.' + wood,
                    lang('%s %s', wood, variant))

    def bucket_item_model(name_parts, fluid):
        res = utils.resource_location(rm.domain, name_parts)
        rm.write(
            (*rm.resource_dir, 'assets', res.domain, 'models', 'item',
             res.path), {
                 'parent': 'forge:item/bucket',
                 'loader': 'forge:bucket',
                 'fluid': fluid
             })
        return rm.item(name_parts)

    # Fluids
    def water_based_fluid(name: str):
        rm.blockstate(('fluid', name)).with_block_model(
            {'particle': 'minecraft:block/water_still'}, parent=None)
        rm.fluid_tag(name, 'tfc:%s' % name, 'tfc:flowing_%s' % name)
        rm.fluid_tag('minecraft:water', 'tfc:%s' % name, 'tfc:flowing_%s' %
                     name)  # Need to use water fluid tag for behavior
        rm.fluid_tag('mixable', 'tfc:%s' % name, 'tfc:flowing_%s' % name)

        item = bucket_item_model(('bucket', name), 'tfc:%s' % name)
        item.with_lang(lang('%s bucket', name))

    def molten_fluid(name: str):
        rm.blockstate(
            ('fluid', 'metal',
             metal)).with_block_model({'particle': 'block/lava_still'},
                                      parent=None)
        rm.fluid_tag(metal, 'tfc:metal/%s' % metal,
                     'tfc:metal/flowing_%s' % metal)

        item = bucket_item_model(('bucket', 'metal', name), 'tfc:%s' % name)
        item.with_lang(lang('molten %s bucket', name))

    water_based_fluid('salt_water')
    water_based_fluid('spring_water')

    # Mixable tags for vanilla water
    rm.fluid_tag('mixable', '#minecraft:water')

    for metal in METALS.keys():
        molten_fluid(metal)

    # Thin Spikes: Calcite + Icicles
    for variant, texture in (('calcite', 'tfc:block/calcite'),
                             ('icicle', 'minecraft:block/ice')):
        block = rm.blockstate(variant,
                              variants={
                                  'tip=true': {
                                      'model': 'tfc:block/%s_tip' % variant
                                  },
                                  'tip=false': {
                                      'model': 'tfc:block/%s' % variant
                                  }
                              })
        block.with_item_model()
        block.with_lang(lang(variant))

        rm.block_model(variant,
                       textures={
                           '0': texture,
                           'particle': texture
                       },
                       parent='tfc:block/thin_spike')
        rm.block_model(variant + '_tip',
                       textures={
                           '0': texture,
                           'particle': texture
                       },
                       parent='tfc:block/thin_spike_tip')

    # Misc Items
    rm.item_model('mortar').with_lang(lang('mortar')).with_tag('tfc:mortar')

    def corals(color: str, dead: bool):
        # vanilla and tfc have a different convention for dead/color order
        left = 'dead_' + color if dead else color
        right = color + '_dead' if dead else color

        rm.blockstate('coral/%s_coral' % right,
                      'minecraft:block/%s_coral' % left)
        rm.blockstate('coral/%s_coral_fan' % right,
                      'minecraft:block/%s_coral_fan' % left)
        rm.blockstate(
            'coral/%s_coral_wall_fan' % right,
            variants=dict(('facing=%s' % d, {
                'model': 'minecraft:block/%s_coral_wall_fan' % left,
                'y': r
            }) for d, r in (('north', None), ('east', 90), ('south', 180),
                            ('west', 270))))

        for variant in ('coral', 'coral_fan', 'coral_wall_fan'):
            rm.item_model('coral/%s_%s' % (right, variant),
                          'minecraft:block/%s_%s' % (left, variant))
            rm.lang('block.tfc.coral.%s_%s' % (right, variant),
                    lang('%s %s', left, variant))

        if not dead:
            # Tag contents are used for selecting a random coral to place by features
            rm.block_tag('wall_corals', 'coral/%s_coral_wall_fan' % color)
            rm.block_tag('corals', 'coral/%s_coral' % color,
                         'coral/%s_coral_fan' % color)

    for color in ('tube', 'brain', 'bubble', 'fire', 'horn'):
        corals(color, False)
        corals(color, True)