thought
Ah! The second execution started a new execution session context or redefined the functions, so `create_corrugated_sheet` is not defined in the scope if we didn't include it in the same code execution.
Let's make sure our script has ALL functions defined together so there are no missing references!
Let's compile a script that contains:
1. `create_corrugated_sheet`
2. `create_weathered_walls_mesh`
3. `create_corrugated_roof`
4. A function to create gable walls.
Wait, let's also make wood support rafters!
Dilapidated rafters under the roof will look gorgeous. They are simple wood beams (long skinny bricks) spanning from wall tops to the peak. Let's make some of them.
Let's see: we want them spaced out along the length of the house.
Let's write a python function to generate rafters:
```python
def add_rafters(name, length=6.0, width=4.0, wall_h=2.5, peak_h=3.6):
    ...
```
This is a great idea. We can generate them inside the house compilation.

Let's also generate a beautiful stone foundation or random stone blocks scattered around.
Let's also write a function to generate **Vines/Ivy (overgrown foliage)**!
How can we generate vine meshes?
We can create a branch-like structure using curves or a procedural mesh of creeping vines.
Wait, a super effective and visually stunning way to generate creeping vines climbing over the roofs and walls is to generate a series of curved or straight vine stems with leaves scattered along them!
Let's write a python function `generate_ivy(target_obj_name, name_prefix, num_vines=5)`:
- We can find points on the target object (like walls or roofs).
- We can trace paths (like a random walk climbing upwards and crawling).
- For each path, we can create a nice thin Bezier curve or a cylinder chain.
- Along the curve, we can instantiate tiny green leaves (planes with the foliage material).
- This is extremely powerful, looks organic, and is incredibly satisfying for an "abandoned village Reclamation" theme!
Let's design a Python function that does exactly this:
- Take a starting position (on the ground against the wall).
- Generate a climbing path: each step goes upwards (Z increases) and snakes left/right (X or Y varies) or clings to the wall surface.
- For the roof, the vine can climb from the wall top up the slope of the roof towards the peak!
- To make a vine, we can represent it as a series of connected cylindrical or curve segments. Or, even simpler and faster to render, we can represent it as a single mesh (using the trunk/vines material) and small leaf meshes (planes) populated at the joints.
Let's write code to do this.

Let's test this logic of a cohesive, beautiful decayed house with walls, roof, rafters, gable walls, and climbing ivy. I will write a script that implements this whole house generation, and let's run it. This will be the main generator for our assets! Let's draft it.

Combine wall and roof generation into robust unified scene setup script

import bpy
import math
import random
from mathutils import Vector, Euler, Matrix

# Clear any previous test objects to avoid duplicates
for obj in ["TestWalls", "TestRoof", "TestSheet"]:
    if obj in bpy.data.objects:
        bpy.data.objects.remove(bpy.data.objects[obj], do_unlink=True)

def create_corrugated_sheet(name, w=1.0, l=1.8, wave_h=0.025, wave_num=6):
    mesh = bpy.data.meshes.new(name)
    obj = bpy.data.objects.new(name, mesh)
    bpy.context.collection.objects.link(obj)

    verts = []
    faces = []
    steps = wave_num * 4

    for j in range(2):
        y = -l/2.0 if j == 0 else l/2.0
        for i in range(steps + 1):
            t = i / steps
            x = -w/2.0 + t * w
            z = wave_h * math.sin(t * wave_num * 2.0 * math.pi)
            verts.append((x, y, z))

    for i in range(steps):
        v1 = i
        v2 = i + 1
        v3 = v2 + (steps + 1)
        v4 = v1 + (steps + 1)
        faces.append((v1, v4, v3, v2))

    mesh.from_pydata(verts, [], faces)
    mesh.update()

    solidify = obj.modifiers.new(name="Solidify", type='SOLIDIFY')
    solidify.thickness = 0.008

    mat = bpy.data.materials.get("Rusted_Metal")
    if mat:
        obj.data.materials.append(mat)

    # Smooth shade
    bpy.ops.object.select_all(action='DESELECT')
    obj.select_set(True)
    bpy.context.view_layer.objects.active = obj
    bpy.ops.object.shade_smooth()

    return obj

def create_weathered_walls_mesh(name, length=6.0, width=4.0, height=2.5):
    all_verts = []
    all_faces = []
    p_w = 0.22
    p_d = 0.025

    def add_box(pos, size, rot):
        v_offset = len(all_verts)
        sx, sy, sz = size[0]/2.0, size[1]/2.0, size[2]/2.0
        local_verts = [
            Vector((-sx, -sy, -sz)), Vector((sx, -sy, -sz)),
            Vector((sx, sy, -sz)), Vector((-sx, sy, -sz)),
            Vector((-sx, -sy, sz)), Vector((sx, -sy, sz)),
            Vector((sx, sy, sz)), Vector((-sx, sy, sz))
        ]
        mat = Matrix.Translation(pos) @ rot.to_matrix().to_4x4()
        for lv in local_verts:
            all_verts.append(mat @ lv)
        local_faces = [
            (0, 1, 2, 3), (4, 7, 6, 5), (0, 4, 5, 1),
            (1, 5, 6, 2), (2, 6, 7, 3), (3, 7, 4, 0)
        ]
        for lf in local_faces:
            all_faces.append((lf[0]+v_offset, lf[1]+v_offset, lf[2]+v_offset, lf[3]+v_offset))

    # Front Wall (Y = -width/2)
    num_steps_x = int(length / p_w)
    for i in range(num_steps_x + 1):
        x = -length/2.0 + i * p_w
        if abs(x) < 0.6:  # door opening
            continue
        if random.random() < 0.12:
            continue
        plank_h = height
        tilted_angle = 0.0
        pos_offset_z = 0.0
        if random.random() < 0.15:
            plank_h = height * random.uniform(0.1, 0.6)
            pos_offset_z = - (height - plank_h) / 2.0
        if random.random() < 0.25:
            tilted_angle = random.uniform(-0.10, 0.10)
        pos = Vector((x + random.uniform(-0.01, 0.01), -width/2.0 + random.uniform(-0.01, 0.01), height/2.0 + pos_offset_z))
        rot = Euler((0.0, tilted_angle, random.uniform(-0.04, 0.04)))
        add_box(pos, (p_w * 0.95, p_d, plank_h), rot)

    # Back Wall (Y = width/2)
    for i in range(num_steps_x + 1):
        x = -length/2.0 + i * p_w
        if abs(x) < 0.6 and random.random() < 0.5:
            continue
        if random.random() < 0.12:
            continue
        plank_h = height
        tilted_angle = 0.0
        pos_offset_z = 0.0
        if random.random() < 0.15:
            plank_h = height * random.uniform(0.1, 0.6)
            pos_offset_z = - (height - plank_h) / 2.0
        if random.random() < 0.25:
            tilted_angle = random.uniform(-0.10, 0.10)
        pos = Vector((x + random.uniform(-0.01, 0.01), width/2.0 + random.uniform(-0.01, 0.01), height/2.0 + pos_offset_z))
        rot = Euler((0.0, tilted_angle, random.uniform(-0.04, 0.04)))
        add_box(pos, (p_w * 0.95, p_d, plank_h), rot)

    # Left Wall (X = -length/2)
    num_steps_y = int(width / p_w)
    for i in range(num_steps_y + 1):
        y = -width/2.0 + i * p_w
        if abs(y) < 0.5:  # window
            continue
        if random.random() < 0.12:
            continue
        plank_h = height
        tilted_angle = 0.0
        pos_offset_z = 0.0
        if random.random() < 0.15:
            plank_h = height * random.uniform(0.1, 0.6)
            pos_offset_z = - (height - plank_h) / 2.0
        if random.random() < 0.25:
            tilted_angle = random.uniform(-0.10, 0.10)
        pos = Vector((-length/2.0 + random.uniform(-0.01, 0.01), y + random.uniform(-0.01, 0.01), height/2.0 + pos_offset_z))
        rot = Euler((tilted_angle, 0.0, math.pi/2.0 + random.uniform(-0.04, 0.04)))
        add_box(pos, (p_w * 0.95, p_d, plank_h), rot)

    # Right Wall (X = length/2)
    for i in range(num_steps_y + 1):
        y = -width/2.0 + i * p_w
        if abs(y) < 0.5 and random.random() < 0.5:
            continue
        if random.random() < 0.12:
            continue
        plank_h = height
        tilted_angle = 0.0
        pos_offset_z = 0.0
        if random.random() < 0.15:
            plank_h = height * random.uniform(0.1, 0.6)
            pos_offset_z = - (height - plank_h) / 2.0
        if random.random() < 0.25:
            tilted_angle = random.uniform(-0.10, 0.10)
        pos = Vector((length/2.0 + random.uniform(-0.01, 0.01), y + random.uniform(-0.01, 0.01), height/2.0 + pos_offset_z))
        rot = Euler((tilted_angle, 0.0, math.pi/2.0 + random.uniform(-0.04, 0.04)))
        add_box(pos, (p_w * 0.95, p_d, plank_h), rot)

    # Gable walls (the triangles)
    # Left gable (X = -length/2)
    # We place horizontal planks of decreasing width to fit the triangle
    p_h = 0.20 # plank height for gables
    gable_max_h = height - p_h/2.0
    g_h = peak_h - height
    for j in range(int(g_h / p_h) + 1):
        rel_h = j * p_h
        clamped_rel_h = min(rel_h, g_h)
        plank_w = (1.0 - (clamped_rel_h / g_h)) * width
        if plank_w < 0.1:
            continue
        if random.random() < 0.15: # decay/missing planks in gable
            continue
        pos = Vector((-length/2.0, random.uniform(-0.01, 0.01), height + clamped_rel_h + p_h/2.0))
        rot = Euler((0.0, 0.0, math.pi/2.0))
        add_box(pos, (plank_w * 0.98, p_d, p_h * 0.95), rot)

    # Right gable (X = length/2)
    for j in range(int(g_h / p_h) + 1):
        rel_h = j * p_h
        clamped_rel_h = min(rel_h, g_h)
        plank_w = (1.0 - (clamped_rel_h / g_h)) * width
        if plank_w < 0.1:
            continue
        if random.random() < 0.15:
            continue
        pos = Vector((length/2.0, random.uniform(-0.01, 0.01), height + clamped_rel_h + p_h/2.0))
        rot = Euler((0.0, 0.0, math.pi/2.0))
        add_box(pos, (plank_w * 0.98, p_d, p_h * 0.95), rot)

    # Compile mesh
    mesh = bpy.data.meshes.new(name)
    obj = bpy.data.objects.new(name, mesh)
    bpy.context.collection.objects.link(obj)

    vert_tuples = [v.to_tuple() for v in all_verts]
    mesh.from_pydata(vert_tuples, [], all_faces)
    mesh.update()

    mat = bpy.data.materials.get("Weathered_Wood")
    if mat:
        obj.data.materials.append(mat)

    return obj

def create_corrugated_roof(name, house_l=6.0, house_w=4.0, wall_h=2.5, peak_h=3.6):
    slope_angle = math.atan((peak_h - wall_h) / (house_w / 2.0))
    slope_len = math.sqrt((house_w/2.0)**2 + (peak_h - wall_h)**2) + 0.35

    sheet_objs = []
    s_w = 0.95
    s_l = 1.35

    for slope_side in [-1, 1]:
        rot_x = slope_side * slope_angle
        cols = int((house_l + 0.4) / (s_w * 0.85)) + 1
        rows = 2

        for r in range(rows):
            for c in range(cols):
                # 22% chance of missing roof sheets to look weathered/looted
                if random.random() < 0.22:
                    continue

                t_slope = 0.25 if r == 0 else 0.75
                dist_along_slope = t_slope * slope_len - 0.15

                local_y = slope_side * (dist_along_slope * math.cos(slope_angle))
                local_z = wall_h + dist_along_slope * math.sin(slope_angle)
                local_x = -house_l/2.0 - 0.1 + c * (s_w * 0.82)

                offset_x = random.uniform(-0.02, 0.02)
                offset_y = random.uniform(-0.02, 0.02)
                offset_z = random.uniform(-0.01, 0.01)

                rot_offset_x = 0.0
                rot_offset_y = 0.0
                rot_offset_z = 0.0

                # Dilapidated slides
                if random.random() < 0.2:
                    offset_y += slope_side * random.uniform(0.12, 0.45)
                    offset_z -= random.uniform(0.04, 0.08)
                    rot_offset_z = random.uniform(-0.18, 0.18)
                    rot_offset_x = random.uniform(-0.04, 0.04)
                elif random.random() < 0.15:
                    rot_offset_z = random.uniform(-0.05, 0.05)

                s_name = f"Sheet_{slope_side}_{r}_{c}"
                # Create sheet in helper
                sheet = create_corrugated_sheet(s_name, w=s_w, l=s_l)
                sheet.location = (local_x + offset_x, local_y + offset_y, local_z + offset_z)
                sheet.rotation_euler = (rot_x + rot_offset_x, rot_offset_y, rot_offset_z)

                sheet_objs.append(sheet)

    if sheet_objs:
        bpy.ops.object.select_all(action='DESELECT')
        for s in sheet_objs:
            s.select_set(True)
        bpy.context.view_layer.objects.active = sheet_objs[0]
        bpy.ops.object.join()
        joined_roof = bpy.context.view_layer.objects.active
        joined_roof.name = name
        return joined_roof
    return None

# Let's run a check!
walls = create_weathered_walls_mesh("Walls_House1")
roof = create_corrugated_roof("Roof_House1")
print("Compiled house successfully!")


Error executing code: Communication error with Blender: Code execution error: name 'peak_h' is not defined