saumwacht-godot/assets-source/phase4/blender/reference_wurzelbund.py
Martin Stickelbroeck c2b447610c Baseline: Saumwacht 0.15.0 (Phase 20A) vor dem Umbau zu Champions of Luneraria
Unveränderter Ausgangsstand inklusive Masterprompt und Konzeptbildern
unter assets/. .godot/ und docs/screenshots/ bleiben laut .gitignore
unversioniert; letztere sind unter ../backups gesichert.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 20:00:36 +02:00

215 lines
10 KiB
Python

"""Living roots, seed heads and fungal canopies from the Phase-3 icons."""
from math import sin,cos,pi
from common import ellipsoid,ring,cylinder,beam
from reference_geometry import r_plate,r_block,r_rock,r_sweep,r_lathe,r_disc
def w_leaf(name,start,end,width,m,colour='accent'):
points=[start,tuple(start[i]*.55+end[i]*.45 for i in range(3)),end]
return r_sweep(name,points,[.015,width,0],m[colour],6,ribbon=True)
def w_flower(name,loc,m,scale=1):
x,y,z=loc
for k in range(5):
a=k*2*pi/5
r_rock(name+'_Petal'+str(k),(x+.038*scale*cos(a),y-.006,z+.038*scale*sin(a)),
(.033*scale,.014*scale,.029*scale),m['light'])
r_rock(name+'_Heart',(x,y-.02,z),(.02*scale,.016*scale,.02*scale),m['accent'])
def w_roots(m,count=4,spread=.43,height=.49,thick=.09):
for k in range(count):
a=2*pi*k/count+pi/4
root=(spread*cos(a),spread*sin(a),.11)
elbow=(spread*.67*cos(a),spread*.67*sin(a),height*.53)
hip=(spread*.28*cos(a),spread*.28*sin(a),height)
r_sweep('Leg_Root'+str(k),[hip,elbow,root],[thick*1.6,thick,thick*.8],m['primary'],6)
r_sweep('Leg_Moss'+str(k),[(hip[0],hip[1]-.025,hip[2]),(elbow[0]+.025,elbow[1]-.03,elbow[2]),
(root[0],root[1]-.025,root[2])],[thick*.32,thick*.22,0],m['secondary'],5)
for j in range(3):
aa=a+(j-1)*.53
tip=(root[0]+.18*cos(aa),root[1]+.18*sin(aa),.015)
r_sweep('Leg_RootToe'+str(k)+'_'+str(j),[root,tip],[thick*.65,0],m['wood'],5)
def w_vine(name,height,radius,m,base=(0,0,.3),phase=0,thickness=.065):
x,y,z=base
points=[]
for k in range(9):
t=k/8
a=phase+t*pi*1.8
points.append((x+radius*cos(a),y+radius*sin(a),z+t*height))
r_sweep(name,points,[thickness*(1-.35*k/8) for k in range(9)],m['primary'],6)
return points
def w_thorn(up,m):
w_roots(m,4 if up else 2,.33,.46,.11)
if not up:
r_rock('Body_MossCore',(0,.02,.79),(.38,.29,.43),m['secondary'])
for k in range(7):
a=2*pi*k/7
p=(.29*cos(a),.23*sin(a),.80)
obj=r_plate('Body_BarkPlate'+str(k),p,[(-.16,.16),(0,.34),(.15,.16),(.13,-.16),(0,-.30),(-.13,-.12)],.10,m['wood'],.05)
obj.rotation_euler=(0,0,a+pi/2)
r_sweep('Body_Thorn'+str(k),[(.36*cos(a),.27*sin(a),.84),(.54*cos(a),.43*sin(a),.97)],
[.085,0],m['accent'],5)
r_plate('Head_EyeSlit',(0,-.306,.77),[(-.19,.024),(.19,.024),(.10,-.012),(-.15,-.016)],.025,m['bark_dark'])
for s in [-1,1]:
r_plate('Head_Eye'+str(s),(s*.115,-.327,.778),[(-.035,.007),(.035,.007),(0,-.01)],.013,m['accent'])
w_leaf('Head_Leaf'+str(s),(0,.03,1.14),(s*.19,.02,1.42),.075,m)
w_flower('Body_Flower',(-.22,-.21,1.03),m)
else:
# The upgrade is a broad open-jawed vine predator, not a round head on sticks.
r_rock('Body_VineMass',(0,.08,.66),(.34,.26,.33),m['primary'])
r_rock('Head_UpperJaw',(0,-.18,1.05),(.42,.40,.20),m['primary'])
r_rock('Head_LowerJaw',(0,-.22,.72),(.38,.39,.12),m['wood'])
r_rock('Head_MouthShadow',(0,-.19,.87),(.29,.23,.19),m['bark_dark'])
for s,side in [(-1,'L'),(1,'R')]:
r_sweep('Head_GreenLip'+side,[(s*.34,.04,1.12),(s*.40,-.22,1.09),(s*.23,-.51,1.06),(0,-.55,1.04)],
[.045,.043,.037,.03],m['secondary'],5)
for k in range(3):
x=s*(.08+k*.12)
y=-.52+k*.06
r_sweep('Head_UpperFang'+side+str(k),[(x,y,1.025),(x,y-.01,.83)],[.045,0],m['wood'],5)
r_sweep('Head_LowerFang'+side+str(k),[(x,y,.73),(x,y,.85)],[.035,0],m['wood'],5)
w_leaf('Head_JawLeaf'+side,(s*.32,-.12,1.03),(s*.48,-.11,1.26),.12,m)
w_flower('Head_JawFlower'+side,(s*.36,-.15,1.10),m,.8)
for k in range(3):
w_vine('Body_BraidedVine'+str(k),.80,.23,m,phase=k*2*pi/3,thickness=.075)
def w_log(name,loc,radius,m):
r_disc(name+'_Bark',loc,radius,.10,m['primary'])
r_disc(name+'_Cut',(loc[0],loc[1]-.065,loc[2]),radius*.88,.038,m['wood'])
for k,f in enumerate([.37,.65]):
ring(name+'_GrowthRing'+str(k),(loc[0],loc[1]-.09,loc[2]),radius*f,
.008,m['bark_dark'],rotation=(pi/2,0,0),segments=10)
def w_tank(up,m):
w_roots(m,4,.43,.58,.12)
r_rock('Body_MossDome',(0,.08,.88),(.48,.35,.46),m['secondary'])
if not up:
for row in range(3):
z=.65+row*.22
radius=.41-row*.085
for k in range(5):
a=k*2*pi/5+row*.55
obj=r_plate('Body_CorkTile'+str(row)+'_'+str(k),(radius*cos(a),.08+radius*.78*sin(a),z),
[(-.16,.11),(.14,.14),(.17,-.08),(0,-.18),(-.15,-.09)],.07,m['wood'],.035)
obj.rotation_euler=(-.25-row*.17,0,a+pi/2)
w_leaf('Body_CrownLeaf',(0,0,1.20),(.23,-.02,1.43),.14,m)
for s in [-1,1]:
w_flower('Body_Flower'+str(s),(s*.27,-.22,1.05),m)
else:
# Large upright stump shields across body/shoulders, no turtle head.
for k,(x,y,z,r) in enumerate([(-.29,-.15,1.02,.32),(.27,-.18,.90,.25),
(0,.02,1.30,.19),(-.37,-.12,.55,.15),(.39,-.12,.55,.14)]):
w_log('Body_LogShield'+str(k),(x,y,z),r,m)
for s in [-1,1]:
w_leaf('Head_Sprout'+str(s),(s*.20,.07,1.33),(s*.36,.08,1.57),.06,m)
w_flower('Body_Flower'+str(s),(s*.36,-.21,1.15),m,.8)
def w_seed_head(name,loc,radius,m,pine=False):
x,y,z=loc
r_lathe(name+'_Cup',loc,[(0,0),(radius*.45,.02),(radius,.21),
(radius*.97,.29),(radius*.77,.27),(radius*.57,.11),(0,.07)],m['secondary'],segments=10)
r_rock(name+'_Seed',(x,y,z+.23),(radius*.59,radius*.58,radius*.52),m['wood'])
if pine:
for layer in range(3):
rr=radius*(1-layer*.18)
for k in range(5):
a=k*2*pi/5+layer*.44
p=(x+rr*.60*cos(a),y+rr*.60*sin(a),z+.10+layer*.12)
outline=[(-rr*.42,-.08),(rr*.42,-.08),(rr*.31,.10),(0,.25),(-rr*.31,.10)]
obj=r_plate(name+'_ConeScale'+str(layer)+'_'+str(k),p,outline,.045,m['wood'])
obj.rotation_euler=(-.25,0,a+pi/2)
else:
for s in [-1,1]:
w_leaf(name+'_LipLeaf'+str(s),(x+s*radius*.8,y,z+.18),(x+s*radius*1.03,y,z+.43),.08,m)
def w_ranged(up,m):
w_roots(m,4 if up else 3,.33,.47,.085)
w_vine('Body_TwistedStem',.68 if up else .76,.09,m,phase=.5,thickness=.07)
w_vine('Body_ClimbingVine',.73,.055,m,phase=3.3,thickness=.038)
w_seed_head('Head_SeedLauncher',(0,-.025,1.02),.29 if up else .23,m,up)
for s in [-1,1]:
w_leaf('Body_BroadLeaf'+str(s),(s*.04,0,.69),(s*.41,-.02,.91),.115,m)
w_flower('Body_Flower'+str(s),(s*.12,-.04,.84),m,.65)
def w_chalice(name,loc,radius,m):
x,y,z=loc
sides=8 if radius<.2 else 12
fringe=3 if radius<.2 else 6
r_lathe(name+'_PinkCup',loc,[(0,0),(radius*.38,.035),(radius*.77,.16),
(radius,.27),(radius*.89,.30),(radius*.65,.17),(0,.065)],m['light'],segments=sides)
ring(name+'_MossRim',(x,y,z+.285),radius*.945,.026 if radius>=.2 else .012,m['accent'],segments=sides)
for k in range(fringe):
a=2*pi*k/fringe
r_sweep(name+'_MossFringe'+str(k),[(x+radius*.96*cos(a),y+radius*.96*sin(a),z+.28),
(x+radius*cos(a),y+radius*sin(a),z+.11-(k%2)*.05)],
[.032,0],m['secondary'],4)
def w_artillery(up,m):
w_roots(m,4,.41,.52,.11)
if up:
positions=[(-.30,-.03,.82,.31),(.28,.03,.74,.30),(0,.10,1.30,.43)]
for k,(x,y,z,r) in enumerate(positions):
r_sweep('Body_FungalTrunk'+str(k),[(x*.3,.08,.40),(x*.80,y,.76),(x,y,z+.03)],
[.12,.085,.065],m['primary'],6)
w_chalice('Head_FungalTier'+str(k),(x,y,z),r,m)
for k in range(3):
x=(-1 if k%2 else 1)*(.35+.04*k)
w_chalice('Body_SmallFungus'+str(k),(x,.04,.55+.12*k),.12,m)
else:
w_vine('Body_ChaliceTrunk',.60,.08,m,thickness=.12)
w_chalice('Head_SporeChalice',(0,0,.93),.48,m)
for k in range(4):
a=k*2*pi/4
r_rock('Weapon_Spore'+str(k),(.14*cos(a),.12*sin(a),1.075),(.065,.055,.10),m['wood'])
for s in [-1,1]:
w_chalice('Body_SideFungus'+str(s),(s*.21,.04,.65),.10,m)
def w_support(up,m):
w_roots(m,4 if up else 3,.39,.50,.10)
if up:
# Open root arch and broad basin form the entire body, without a human face.
for s in [-1,1]:
r_sweep('Body_SpringArch'+str(s),[(s*.31,.10,.40),(s*.40,.11,.83),
(s*.31,.09,1.24),(s*.11,.07,1.43),(0,.07,1.42)],
[.12,.105,.09,.06,.045],m['primary'],6)
r_sweep('Body_FrontVine'+str(s),[(s*.25,-.05,.35),(s*.10,-.11,.60),
(s*.32,-.03,.96),(s*.13,.06,1.29)],
[.07,.07,.06,.02],m['wood'],5)
for k in range(7):
a=k*2*pi/7
w_leaf('Head_CanopyLeaf'+str(k),(.07*cos(a),.08,1.39),(.43*cos(a),.08+.22*sin(a),1.20),.13,m)
for k,(x,z) in enumerate([(-.33,1.25),(.30,1.19),(-.15,1.43),(.34,.89)]):
w_flower('Body_Blossom'+str(k),(x,-.07,z),m)
radius,z=.34,.83
else:
w_vine('Body_LivingTrunk',.91,.07,m,thickness=.10)
w_vine('Body_WindingVine',.95,.12,m,phase=2.7,thickness=.038)
for k,(dx,dz) in enumerate([(-.34,0),(.34,-.02),(.03,.25)]):
w_leaf('Head_LeafCrown'+str(k),(0,.03,1.17),(dx,0,1.33+dz),.14,m)
w_flower('Head_Flower',(-.12,-.05,1.19),m,.8)
radius,z=.25,.72
r_lathe('Weapon_LeafBasin',(0,-.24,z-.12),[(0,0),(radius*.4,.02),(radius,.19),
(radius*.88,.21),(radius*.67,.11),(0,.05)],m['accent'],segments=10)
cylinder('Weapon_Water',(0,-.24,z+.035),radius*.78,.025,m['water'],vertices=12)
for s in [-1,1]:
r_sweep('Arm_BasinVine'+str(s),[(s*.10,0,z+.20),(s*.28,-.09,z+.18),
(s*radius,-.24,z+.025)],[.05,.045,.02],m['primary'],5)
if not up:
r_rock('Weapon_DewOrb',(0,-.24,z+.16),(.12,.10,.13),m['water'])
def build_wurzelbund(spec,m):
{'melee':w_thorn,'tank':w_tank,'ranged':w_ranged,'artillery':w_artillery,'support':w_support}[spec['role']](spec['upgraded'],m)