Add formal enemies, remaining formal partners and synthesized UI SFX
- UI SFX v3: procedurally synthesized one-shots (Tools/synth_ui_sfx.py) wired to buttons, rewards, errors and red dots via UiSfx, gated by the SFX setting. - Five formal enemies (Hornlet, Dashlet, Shellhorn, HornCaptain, GreatHorn): Hunyuan 50k -> 2000-tri XPbr, DGXA TokenRig, Idle/Walk/Attack, nested per type in PrototypeArena; PrototypeBattle.Enemy gains presentation-only Moving/Strikes. - Formal partners for all ten pets in the arena and portraits, including new VineSprite, ThunderLeopard and TideWhale. - Pipeline fixes: reject local TokenRig fallback, drop loose mesh islands, configurable Unity run_script timeout, companion static stage. - Also includes concurrent work from another tool in this working tree (FlameLion, enemy combat FX, challenge mode, home explorer, server updates). - Resources registered in Doc/ResDesc_*.md; verified on isolated :18081. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -157,6 +157,33 @@ def main():
|
||||
# recipe-defined geodesic masks can bind that appendage to an existing
|
||||
# stable bone without changing geometry, UVs or the animation skeleton.
|
||||
override_reports=[]
|
||||
# Explicit source-space regions can bind a rigid carapace without altering
|
||||
# geometry/UVs. The recipe must be fitted to this character's inspected mesh.
|
||||
if args.weight_overrides:
|
||||
rules=json.loads(args.weight_overrides.read_text(encoding='utf-8-sig')).get('skinRegions',[])
|
||||
extent=max(p.y for p in original_points)-min(p.y for p in original_points)
|
||||
points=[p/extent for p in original_points]
|
||||
for rule in rules:
|
||||
if rule['bone'] not in arm.data.bones:raise ValueError('Region bone missing')
|
||||
lo,hi=rule['min'],rule['max'];feather=rule.get('feather',0)
|
||||
if feather<0 or any(lo[c]>=hi[c] for c in range(3)):raise ValueError('Invalid rigid region')
|
||||
target=low.vertex_groups[rule['bone']];affected=[];full=[]
|
||||
for i,p in enumerate(points):
|
||||
distance=max(max(lo[c]-p[c],0,p[c]-hi[c]) for c in range(3))
|
||||
if distance>feather:continue
|
||||
weight=1 if distance==0 else 1-distance/feather
|
||||
weight=weight*weight*(3-2*weight)
|
||||
previous={g.group:g.weight for g in low.data.vertices[i].groups}
|
||||
for group,value in previous.items():low.vertex_groups[group].add([i],value*(1-weight),'REPLACE')
|
||||
target.add([i],previous.get(target.index,0)*(1-weight)+weight,'REPLACE')
|
||||
affected.append(i)
|
||||
if distance==0:full.append(i)
|
||||
if not full:raise ValueError('Rigid region selected no vertices')
|
||||
override_reports.append(dict(kind='source_space_region',bone=rule['bone'],affected=len(affected),full_weight_vertices=len(full),
|
||||
normalized_min=[min(points[i][c] for i in affected) for c in range(3)],
|
||||
normalized_max=[max(points[i][c] for i in affected) for c in range(3)]))
|
||||
|
||||
# More precise geodesic appendage overrides run after broad spatial regions.
|
||||
if args.weight_overrides:
|
||||
overrides=json.loads(args.weight_overrides.read_text(encoding='utf-8-sig')).get('skinOverrides',[])
|
||||
extent=max(p.y for p in original_points)-min(p.y for p in original_points)
|
||||
|
||||
Reference in New Issue
Block a user