Good progress — 8 of 12 trees placed. Adding a second pass to fill gaps, plus shoreline reeds, lily pads, and scattered rocks:

import bpy, math, random
from mathutils import Vector
from mathutils import noise as bnoise

random.seed(77)
scene=bpy.context.scene; CX=6.8; ZW=-0.18

def sm(a,b,x):
    if abs(a-b)<1e-9: return 0.0
    t=min(max((x-a)/(b-a),0.0),1.0); return t*t*(3-2*t)
C=Vector((-7.5,3.0)); R=10.4
def reff(a): return R*(1.0+0.16*math.cos(3*a+math.pi)+0.09*math.sin(2*a))
def fbm(x,y,s=0.0):
    v=0.0;a=1.0;f=0.055;p=Vector((x*f,y*f,7.31+s))
    for i in range(4):
        v+=a*bnoise.noise(p); a*=0.5; p*=2.13
    return v
pads=[(6.8,-4.6,4.6,0.62),(1.6,-1.9,2.0,0.40)]
path_pts=[(6.8,-7.2),(5.4,-5.6),(3.2,-3.4),(1.6,-1.9)]
segs=[]; total_len=0.0
for i in range(len(path_pts)-1):
    ax,ay=path_pts[i]; bx,by=path_pts[i+1]
    L=math.hypot(bx-ax,by-ay); segs.append((ax,ay,bx,by,L,total_len)); total_len+=L
def path_eval(x,y):
    best=(1e9,0.0)
    for ax,ay,bx,by,L,acc in segs:
        abx,aby=bx-ax,by-ay; apx,apy=x-ax,y-ay; L2=L*L
        t=0.0 if L2==0 else min(max((apx*abx+apy*aby)/L2,0.0),1.0)
        px,py=ax+t*abx,ay+t*aby
        d=math.hypot(x-px,y-py)
        if d<best[0]: best=(d,min(max((acc+t*L)/max(total_len,1e-6),0.0),1.0))
    return best
def ground_h(x,y):
    n=fbm(x,y); h=0.55*n
    h+=2.3*math.exp(-(((x+13)**2+(y-17)**2))/288.0)
    h+=1.5*math.exp(-(((x-20)**2+(y-1)**2))/200.0)
    h+=0.9*sm(22,34,math.hypot(x,y))
    dx,dy=x-C.x,y-C.y; d=math.hypot(dx,dy); a=math.atan2(dy,dx)
    fm=sm(R*0.70,R*1.22,d); h*=(0.12+0.88*fm)
    for cx_,cy_,rad,tg in pads:
        pd=math.hypot(x-cx_,y-cy_); t=sm(rad,rad*0.55,pd)
        if t>0:
            tgt=tg+0.10*fbm(x*1.6+9,y*1.6,3.0); h=h*(1-t)+tgt*t
    dp,tt=path_eval(x,y); tp=sm(2.0,0.8,dp)
    if tp>0:
        tgt=0.62+(0.40-0.62)*tt+0.05*fbm(x*2.0,y*2.0,5.0); h=h*(1-tp)+tgt*tp
    rr=9.9
    if d<R*1.35:
        rr=d/max(reff(a),0.001); ins=sm(1.06,0.42,rr)
        if ins>0:
            bed=-1.55+0.07*bnoise.noise(Vector((x*0.7,y*0.7,2.2)))
            h=h*(1-ins)+bed*ins+0.05*fbm(x*1.3,y*1.3,8.0)*ins
    return h,rr,d,a

def dist_to_dock(x,y):
    ax,ay=0.95,-2.45; bx,by=ax+(-0.838)*4.3, ay+(0.546)*4.3
    abx,aby=bx-ax,by-ay; apx,apy=x-ax,y-ay; L2=abx*abx+aby*aby
    t=min(max((apx*abx+apy*aby)/L2,0.0),1.0)
    return math.hypot(x-(ax+t*abx), y-(ay+t*aby))
def site_ok(x,y,min_water_gap=0.28):
    h,rr,d,a=ground_h(x,y)
    if h<ZW+min_water_gap: return None
    dp,tt=path_eval(x,y)
    if dp<1.15: return None
    if abs(x-CX)<5.7 and abs(y)<4.6: return None
    if dist_to_dock(x,y)<1.7: return None
    if math.hypot(x-11.55,y-1.1)<1.7: return None
    return h

def link_to(obj,cname):
    col=bpy.data.collections.get(cname)
    if col is None:
        col=bpy.data.collections.new(cname); scene.collection.children.link(col)
    for c in list(obj.users_collection): c.objects.unlink(obj)
    col.objects.link(obj)

MAT_BARK=bpy.data.materials.get("LogMat")
PINE_M=bpy.data.materials["PineMat"]; LEAF_M=bpy.data.materials["LeafMat"]

def make_pine(name,h_total,r_base):
    parts=[]
    bpy.ops.mesh.primitive_cone_add(vertices=8, radius1=r_base, radius2=r_base*0.45,
                                    depth=h_total*0.62, location=(0,0,h_total*0.31))
    tr=bpy.context.active_object; tr.data.materials.append(MAT_BARK); parts.append(tr)
    nf=7
    for i in range(nf):
        f0=i/nf; f1=(i+1)/nf
        cz0=h_total*(0.24+0.76*f0); cz1=h_total*(0.24+0.76*f1)
        r0=r_base*(2.6-2.0*f0)*(1+random.uniform(-0.08,0.08))
        r1=max(r_base*(2.6-2.0*f1)*0.92, r_base*0.28)
        hh=cz1-cz0+h_total*0.06
        bpy.ops.mesh.primitive_cone_add(vertices=9, radius1=r0, radius2=r1,
                                        depth=hh,
                                        location=(random.uniform(-0.08,0.08),
                                                  random.uniform(-0.08,0.08),(cz0+cz1)/2))
        fo=bpy.context.active_object
        for p in fo.data.polygons: p.use_smooth=True
        fo.rotation_euler=(0,0,random.uniform(0,6.28))
        fo.scale=(1,random.uniform(0.88,1.05),1)
        fo.data.materials.append(PINE_M); parts.append(fo)
    for ob in parts: link_to(ob,"Trees")
    bpy.ops.object.select_all(action='DESELECT')
    for ob in parts: ob.select_set(True)
    bpy.context.view_layer.objects.active=parts[0]
    bpy.ops.object.join()
    tree=bpy.context.active_object; tree.name=name
    return tree

def make_broadleaf(name,h_trunk,r_can):
    parts=[]
    bpy.ops.mesh.primitive_cone_add(vertices=8, radius1=0.16, radius2=0.11,
                                    depth=h_trunk, location=(0,0,h_trunk/2))
    tr=bpy.context.active_object
    for p in tr.data.polygons: p.use_smooth=True
    tr.data.materials.append(MAT_BARK); parts.append(tr)
    for k in range(3):
        br_len=h_trunk*0.55
        bpy.ops.mesh.primitive_cone_add(vertices=6, radius1=0.06, radius2=0.03, depth=br_len)
        br=bpy.context.active_object
        az=random.uniform(0,6.28); pol=math.radians(random.uniform(38,60))
        br.rotation_euler=(pol*math.cos(az), pol*math.sin(az), 0)
        off=Vector((math.sin(pol)*math.cos(az), math.sin(pol)*math.sin(az), math.cos(pol)))*br_len/2
        br.location=Vector((0,0,h_trunk*0.86))+off
        br.data.materials.append(MAT_BARK); parts.append(br)
    nb=5
    for k in range(nb):
        bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=2,
            radius=r_can*random.uniform(0.55,0.85),
            location=(h_trunk*0.16+random.uniform(-r_can*0.7,r_can*0.7),
                      random.uniform(-r_can*0.7,r_can*0.7),
                      h_trunk+r_can*0.35+random.uniform(-0.25*r_can,0.5*r_can)))
        bl=bpy.context.active_object
        for v in bl.data.vertices:
            v.co += Vector(v.normal)*random.uniform(-0.08,0.08)*r_can
        for p in bl.data.polygons: p.use_smooth=True
        bl.scale=(1.0,random.uniform(0.85,1.0),random.uniform(0.75,0.9))
        bl.data.materials.append(LEAF_M); parts.append(bl)
    for ob in parts: link_to(ob,"Trees")
    bpy.ops.object.select_all(action='DESELECT')
    for ob in parts: ob.select_set(True)
    bpy.context.view_layer.objects.active=parts[0]
    bpy.ops.object.join()
    tree=bpy.context.active_object; tree.name=name
    return tree

placed={}
specs=[
 ("pine","PineSW5",-6.0,-13.0,1.10,6.4,0.30),
 ("pine","PineS6",-11.5,-9.0,1.20,6.9,0.32),
 ("broad","OakS",-1.0,-17.0,1.15,3.3,2.5),
 ("pine","PineW7",-16.5,1.0,1.25,7.1,0.33),
 ("broad","MapleCabinN",0.5,7.0,0.95,3.0,2.2),
 ("pine","PineNE8",16.0,12.0,1.15,6.7,0.32),
]
for kind,nm,x,y,sc,ht,rb in specs:
    h=site_ok(x,y)
    if h is None: placed[nm]=False; continue
    maker=make_pine if kind=="pine" else make_broadleaf
    t=maker(nm,ht*sc,rb*sc)
    t.location=(x,y,h-0.12)
    t.rotation_euler=(0,0,random.uniform(0,6.28))
    placed[nm]=True

# ---------- rocks ----------
ROCK_M = bpy.data.materials.get("StoneMat")
rock_specs=[(-2.6,7.6,0.55),(12.9,4.9,0.5),(2.9,-8.3,0.42),(13.4,-2.2,0.38),
            (-4.4,-8.9,0.46),(0.4,-6.6,0.34),(14.6,7.4,0.52),(9.3,8.9,0.4),
            (-9.2,-5.4,0.44),(4.4,10.2,0.48)]
nr=0
for i,(rx,ry,sz_) in enumerate(rock_specs):
    h,rr,d,a=ground_h(rx,ry)
    if h<ZW+0.12: continue
    bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=1, radius=sz_, location=(rx,ry,h+sz_*0.25))
    rk=bpy.context.active_object; rk.name=f"Rock{i}"
    for v in rk.data.vertices:
        v.co += Vector(v.normal)*random.uniform(-0.22,0.28)*sz_
        v.co.z *= 0.72
    rk.scale=(random.uniform(0.85,1.3),random.uniform(0.85,1.3),1)
    rk.rotation_euler=(random.uniform(0,0.3),random.uniform(0,0.3),random.uniform(0,6.28))
    for p in rk.data.polygons: p.use_smooth=True
    rk.data.materials.append(ROCK_M)
    link_to(rk,"Props"); nr+=1

# ---------- reeds / cattails ----------
reed_specs=[(-1.9,-1.3),(2.3,7.3),(-4.6,6.9),(9.6,-3.4),(11.9,4.4),(-0.6,-4.3),
            (12.9,1.9),(-3.3,4.6),(8.4,8.2),(3.1,9.3)]
stem_m = MAT_BARK
tip_mat = bpy.data.materials.new("CattailTip"); tip_mat.use_nodes=True
ntt=tip_mat.node_tree; ntt.nodes.clear()
ot=ntt.nodes.new('ShaderNodeOutputMaterial'); et=ntt.nodes.new('ShaderNodeEmission')
et.inputs['Color'].default_value=(0.28,0.14,0.06,1); et.inputs['Strength'].default_value=0.35
ntt.links.new(et.outputs['Emission'], ot.inputs['Surface'])
nreeds=0
for i,(rx,ry) in enumerate(reed_specs):
    h,rr,d,a=ground_h(rx,ry)
    wl = ZW - 0.02
    base_z = max(h, wl-0.35)
    if h > ZW+0.35:   # too far above waterline; skip
        continue
    grp=[]
    for k in range(random.randint(5,8)):
        ang=random.uniform(0,6.28); rad=random.uniform(0,0.28)
        px,py=rx+math.cos(ang)*rad, ry+math.sin(ang)*rad
        hh=random.uniform(0.8,1.5)
        bpy.ops.mesh.primitive_cone_add(vertices=5, radius1=0.022, radius2=0.004,
                                        depth=hh,
                                        location=(px,py,wl+hh/2-0.15))
        st=bpy.context.active_object
        st.rotation_euler=(random.uniform(-0.09,0.09),random.uniform(-0.09,0.09),0)
        st.data.materials.append(stem_m)
        grp.append(st)
        if random.random()<0.5:
            bpy.ops.mesh.primitive_cylinder_add(vertices=6, radius=0.028, depth=0.16,
                                                location=(px,py,wl+hh-0.12))
            tp=bpy.context.active_object
            tp.rotation_euler=st.rotation_euler
            tp.data.materials.append(tip_mat)
            grp.append(tp)
    for ob in grp: link_to(ob,"Props")
    bpy.ops.object.select_all(action='DESELECT')
    for ob in grp: ob.select_set(True)
    bpy.context.view_layer.objects.active=grp[0]
    bpy.ops.object.join()
    j=bpy.context.active_object; j.name=f"Reeds{i}"
    nreeds+=1

# ---------- lily pads ----------
pad_mat = bpy.data.materials.new("LilyPad"); pad_mat.use_nodes=True
nl_=pad_mat.node_tree; nl_.nodes.clear()
ol_=nl_.nodes.new('ShaderNodeOutputMaterial'); bl_=nl_.nodes.new('ShaderNodeBsdfPrincipled')
bl_.inputs['Base Color'].default_value=(0.045,0.115,0.038,1)
bl_.inputs['Roughness'].default_value=0.55
nl_.links.new(bl_.outputs['BSDF'], ol_.inputs['Surface'])
lily_specs=[(0.3,1.6),(-1.4,0.4),(1.5,3.1),(0.9,4.4),(-0.8,2.6),(2.6,2.0),(1.9,5.3)]
nlily=0
for i,(lx,ly) in enumerate(lily_specs):
    h,rr,d,a=ground_h(lx,ly)
    if h>-0.55: continue
    bpy.ops.mesh.primitive_circle_add(vertices=12, radius=random.uniform(0.16,0.3),
                                      fill_type='NGON', location=(lx,ly,ZW+0.015))
    lp=bpy.context.active_object; lp.name=f"LilyPad{i}"
    lp.rotation_euler=(0,0,random.uniform(0,6.28))
    lp.data.materials.append(pad_mat)
    link_to(lp,"Water"); nlily+=1
    # tiny flower on some
    if random.random()<0.4:
        bpy.ops.mesh.primitive_uv_sphere_add(radius=0.05, location=(lx,ly,ZW+0.05))
        fl=bpy.context.active_object; fl.name=f"LilyFlower{i}"
        fm2=bpy.data.materials.new("LilyFlower"); fm2.use_nodes=True
        nf2=fm2.node_tree; nf2.nodes.clear()
        of2=nf2.nodes.new('ShaderNodeOutputMaterial'); bf2=nf2.nodes.new('ShaderNodeBsdfPrincipled')
        bf2.inputs['Base Color'].default_value=(0.92,0.88,0.90,1); bf2.inputs['Roughness'].default_value=0.6
        nf2.links.new(bf2.outputs['BSDF'], of2.inputs['Surface'])
        fl.data.materials.append(fm2)
        link_to(fl,"Water")

result={"trees2":placed,"rocks":nr,"reeds":nreeds,"lilies":nlily}