; ; /* ============================================================================ MACHINE ASCENDANCY — PROCEDURAL STRUCTURE LIBRARY ---------------------------------------------------------------------------- Load after engine/models.js. The Machine language is deliberately not a purple repaint of Terran concrete: triangular plans, separated/floating mechanisms, radial cages and exposed energy throats carry the faction read. Every visible finish is zoned onto the existing mobile material atlas. This adds no texture, sampler or draw-call class; the new colours are selectors for the six tower PBR cells already paid for by materials.js. ============================================================================ */ /* Coalition hardware used the same violet glow/black shell family as Brood tissue. The meshes were correct, but at phone zoom the palette collapsed both factions into the same read. Advanced-machine energy is now cyan/blue over brighter naval steel; violet remains exclusive to the organic hive. */ const MAC_ARM=C(124,152,178), MAC_ARM_D=C(37,54,72); const MAC_PANEL=C(154,179,202), MAC_EDGE=C(208,232,246); const MAC_MECH=C(136,166,190), MAC_TRIM=C(204,232,246); const MAC_COAT=C(18,33,48), MAC_GLOW=C(52,198,255); const MAC_GLOW_HI=C(178,241,255), MAC_STATUS=C(88,216,255), MAC_PAD=C(56,76,94); const MAC_BORE=C(5,13,20), MAC_TEAM=C(104,176,238); COL_MAT.set(MAC_ARM,MAT.TWR_ARMOR); COL_MAT.set(MAC_ARM_D,MAT.TWR_COAT); COL_MAT.set(MAC_PANEL,MAT.TWR_ARMOR); COL_MAT.set(MAC_EDGE,MAT.TWR_MACH); COL_MAT.set(MAC_MECH,MAT.TWR_MACH); COL_MAT.set(MAC_TRIM,MAT.TWR_MACH); COL_MAT.set(MAC_COAT,MAT.TWR_COAT); COL_MAT.set(MAC_GLOW,MAT.TWR_GLOW); COL_MAT.set(MAC_GLOW_HI,MAT.TWR_GLOW); COL_MAT.set(MAC_STATUS,MAT.TWR_GLOW); COL_MAT.set(MAC_PAD,MAT.TWR_PAD); COL_MAT.set(MAC_BORE,MAT.TWR_BORE); COL_MAT.set(MAC_TEAM,MAT.TWR_ARMOR); COL_TEAM.add(MAC_TEAM); function macPoly(n,r,rot){ const p=[]; rot=rot||0; for(let i=0;i0?MAC_GLOW:MAC_STATUS); } if((tier||1)>1) m.box(x-w*.38,y+h*.36,0,.5,h*.42,gap*1.62,MAC_EDGE); return m; } function macPylon(m,a,r,y,h,w,lit){ const x=Math.cos(a)*r,z=Math.sin(a)*r, yaw=a+Math.PI/2; m.extrude(x,y,z,macTri(w),h,MAC_ARM_D,yaw); m.extrude(x,y+h,z,macTri(w*.72),3.0,a<0?MAC_TEAM:MAC_PANEL,yaw); m.box(x,y+h*.66,z,w*.58,.34,w*.25,MAC_EDGE,yaw); m.box(x,y+h*.42,z,w*.42,h*.48,.55,MAC_COAT,yaw); if(lit!==false) m.box(x,y+h*.47,z,w*.18,h*.34,.60,a<0?MAC_STATUS:MAC_GLOW,yaw); return m; } function macPad(m,r,tier,core){ tier=tier||1; m.extrude(0,0,0,macHex(r),2.8,MAC_PAD); m.extrude(0,2.8,0,macTri(r*.91),3.5,MAC_ARM_D); m.extrude(0,6.3,0,macHex(r*.67),3.6,MAC_PANEL); m.ring(0,10.0,0,r*.38,r*.55,24,MAC_COAT); m.ring(0,10.15,0,r*.47,r*.51,24,MAC_GLOW); for(let i=0;i<3;i++){ const a=-Math.PI/2+i*TAU/3,x=Math.cos(a)*r*.73,z=Math.sin(a)*r*.73; m.bevelBox(x,2.8,z,r*.28,4.2,r*.20,.55,i===0?MAC_TEAM:MAC_COAT,a); m.box(x,6.68,z,r*.20,.24,r*.12,MAC_EDGE,a); macGlowBar(m,x,7.1,z,r*.16,r*.06,a,i===0?MAC_STATUS:MAC_GLOW); if(tier>1) m.cyl(x,7.0,z,r*.055,r*.035,4.1,7,MAC_MECH); } if(tier>2) for(let i=0;i<6;i++){ const a=i*TAU/6,x=Math.cos(a)*r*.58,z=Math.sin(a)*r*.58; m.sphere(x,10.8,z,.62,7,MAC_GLOW,1,false); } if(core) m.tube(0,9.9,0,r*.31,r*.19,1.2,18,MAC_BORE); return m; } function macCore(m,x,y,z,r,axes){ m.sphere(x,y,z,r,12,MAC_GLOW,1,false); m.ring(x,y,z,r*1.25,r*1.48,24,MAC_EDGE); if(axes!==false){ ringX(m,x,y,z,r*1.38,r*1.58,22,MAC_ARM); m.cyl(x,y-r*1.45,z,r*1.55,r*1.55,.32,22,MAC_GLOW_HI); } return m; } function macCrown(m,y,r,n){ for(let i=0;i0?MAC_GLOW:MAC_STATUS); macPylon(m,s*Math.PI/2,30,4,27,4.8,true); } macPortal(m,22,23,0,10,15); m.box(-5,12,0,40,2.0,18,MAC_COAT); m.extrude(-9,14.05,0,macTri(8.2),.52,MAC_PANEL); m.greeble(-9,14,0,30,14,2.2,10,MAC_MECH,0,71); macCore(m,-23,29,0,3.6,false); return m.build(); } function mdlMacAirfield(){ const m=MB(); m.extrude(0,0,0,[[-46,-28],[31,-28],[48,0],[31,28],[-46,28],[-35,0]],3,MAC_PAD); m.extrude(-4,3,0,[[-37,-22],[28,-22],[39,0],[28,22],[-37,22],[-29,0]],3,MAC_ARM_D); for(const s of [-1,1]){ m.box(-3,6,s*13,60,.55,3.0,MAC_GLOW); m.bevelBox(-28,6,s*22,20,8,7,1.0,MAC_ARM_D); m.box(-28,14.05,s*22,11,.35,3.4,MAC_PANEL); macPylon(m,s*Math.PI/2,27,3,18,3.4,true); } m.ring(22,6.7,0,9,13,28,MAC_ARM); m.ring(22,6.9,0,10.8,11.7,28,MAC_GLOW); m.bevelBox(-35,6,0,14,17,30,1.5,MAC_ARM); m.bevelBox(-35,23.05,0,9,1.4,22,.35,MAC_PANEL); macPortal(m,-27.8,19,0,5,8); return m.build(); } function mdlMacHarbor(){ const m=MB(); m.extrude(0,0,0,[[-42,-28],[26,-28],[40,-15],[18,-8],[18,8],[40,15],[26,28],[-42,28]],4,MAC_PAD); for(const s of [-1,1]){ m.bevelBox(-5,4,s*21,64,7,8,1.0,MAC_ARM_D); m.box(-3,11.05,s*21,48,.42,4.2,MAC_PANEL); macGlowBar(m,-3,11.5,s*21,28,.8,0,s>0?MAC_GLOW:MAC_STATUS); macPylon(m,s*Math.PI/2,30,4,22,4.0,true); } m.bevelBox(-30,4,0,20,19,34,2.0,MAC_ARM); m.bevelBox(-30,23.05,0,13,1.5,24,.4,MAC_PANEL); macPortal(m,-19,21,0,6.5,10); return m.build(); } function mdlMacHQ(){ const m=MB(); m.extrude(0,0,0,macHex(47),4,MAC_PAD); m.extrude(0,4,0,macTri(41),8,MAC_ARM_D); m.extrude(0,12,0,macHex(29),10,MAC_ARM); m.extrude(-7,22,0,macTri(22),13,MAC_ARM_D); m.extrude(-7,35.05,0,macTri(15),1.2,MAC_PANEL); for(let i=0;i<3;i++){ const a=-Math.PI/2+i*TAU/3; macPylon(m,a,35,4,36,7.0,true); const x=Math.cos(a)*29,z=Math.sin(a)*29; m.bevelBox(x,9,z,15,14,15,1.8,MAC_COAT,a); } macCore(m,-7,40,0,8.0,true); m.ring(0,22.4,0,25,29,30,MAC_COAT); m.ring(0,22.7,0,26.5,27.5,30,MAC_GLOW); macPortal(m,31,25,0,8,12); macCrown(m,44,24,6); return m.build(); } function mdlMacTechlab(){ const m=MB(); macPad(m,24,1,false); m.extrude(0,9.8,0,macTri(16),11,MAC_ARM_D); for(let i=0;i<3;i++) macPylon(m,-Math.PI/2+i*TAU/3,16.5,9,25,4.5,true); macCore(m,0,28,0,6.6,true); ringX(m,0,28,0,9.0,10.2,28,MAC_MECH); m.ring(0,20.6,0,12,14,28,MAC_GLOW); return m.build(); } function mdlMacUplink(){ const m=MB(); macPad(m,20,2,false); m.extrude(0,9.8,0,macTri(9.5),29,MAC_ARM_D); m.extrude(0,38.8,0,macTri(5.8),8,MAC_ARM); for(let y=17;y<42;y+=7) m.ring(0,y,0,8.5-(y-17)*.10,9.4-(y-17)*.10,22,MAC_GLOW); macPortal(m,0,49,0,6.5,9.5); macCrown(m,38,12,3); return m.build(); } function mdlMacShield(){ const m=MB(); macPad(m,20,1,false); for(let i=0;i<3;i++) macPylon(m,-Math.PI/2+i*TAU/3,13,9,22,3.8,true); macCore(m,0,26,0,7.0,true); m.ring(0,17,0,10,13.5,26,MAC_ARM); m.ring(0,17.3,0,11.3,12.2,26,MAC_GLOW); return m.build(); } function mdlMacTargetGate(){ const m=MB(); macPad(m,17,1,false); for(const s of [-1,1]){ m.extrude(0,9.8,s*8,macTri(5.5),24,MAC_ARM_D,s*.22); m.box(0,20,s*8,1.0,11,2.5,MAC_GLOW); } macPortal(m,0,28,0,6.2,9.2); m.sphere(0,28,0,2.0,8,MAC_GLOW_HI,1,false); return m.build(); } function mdlMacRelayNest(){ const m=MB(); macPad(m,19,1,false); m.extrude(0,9.8,0,macHex(12),12,MAC_ARM_D); for(let i=0;i<6;i++){ const a=i*TAU/6,x=Math.cos(a)*10,z=Math.sin(a)*10; m.tube(x,20,z,2.4,1.25,3.0,10,MAC_BORE); m.sphere(x,24,z,1.0,7,MAC_GLOW,1,false); } macCore(m,0,27,0,4.5,false); return m.build(); } /* ---- walls and gates ----------------------------------------------------- */ function mdlMacWall(){ const m=MB(); m.extrude(0,0,0,[[-15,-9],[12,-9],[16,0],[12,9],[-15,9],[-11,0]],3,MAC_PAD); m.bevelBox(0,3,0,28,11,11,1.5,MAC_ARM_D); m.extrude(0,14,0,[[-14,-5],[10,-5],[14,0],[10,5],[-14,5],[-10,0]],5,MAC_ARM); m.box(0,19.05,0,18,.44,6.5,MAC_PANEL); for(const x of [-10,0,10]){ m.box(x,5,-5.7,1.4,11,.55,MAC_GLOW); m.box(x,5,5.7,1.4,11,.55,MAC_GLOW); } for(const x of [-13,13]) m.extrude(x,3,0,macTri(4.2),18,MAC_COAT,x<0?-.2:.2); m.box(-13,11.5,-4.25,2.2,5,.38,MAC_TEAM,-.2); return m.build(); } function mdlMacGate(){ const m=MB(); m.extrude(0,0,0,[[-16,-10],[12,-10],[17,0],[12,10],[-16,10],[-12,0]],3,MAC_PAD); for(const s of [-1,1]){ m.extrude(s*11,3,0,macTri(6.5),24,MAC_ARM_D,s*.18); m.extrude(s*11,27,0,macTri(4.3),4,s<0?MAC_TEAM:MAC_PANEL); m.box(s*11,9,0,1.5,14,5,MAC_GLOW); } m.box(0,23,0,20,4,8,MAC_COAT); m.box(0,4,0,17,18,.55,MAC_GLOW); macPortal(m,0,25,0,4.5,6.2); return m.build(); } /* ---- eight contact-sheet defensive archetypes -------------------------- */ function mdlMacGravityBase(tier){ const m=MB(); tier=tier||1; macPad(m,22,tier,true); for(let i=0;i<3;i++) macPylon(m,-Math.PI/2+i*TAU/3,15.5,9,11+tier,4.2,true); m.tube(0,10,0,8.2,5.5,6.0,22,MAC_BORE); m.ring(0,16.1,0,9.0,12.0,28,MAC_ARM); m.ring(0,16.4,0,10.2,11.0,28,MAC_GLOW); macAimBearing(m,16.7,7.8,tier); return m.build(); } function mdlMacGravityTur(tier){ const m=MB(); tier=tier||1; m.cyl(0,0,0,7.9,7.3,2.0,18,MAC_MECH); m.bevelBox(-3.5,2.0,0,15+tier,7.5,15+tier,1.2,MAC_ARM); macCheeks(m,-4,4.3,7.55+tier*.5,8.5,2.5,tier); tubeX(m,2.5,7.2,0,15+tier*2.5,3.2+tier*.2,1.22+tier*.08,18,MAC_BORE); for(const x of [4,10,16]) ringX(m,x,7.2,0,3.5+tier*.2,4.2+tier*.2,20,x===16?MAC_GLOW:MAC_EDGE); macCore(m,-8,9.0,0,3.2+tier*.35,false); for(const s of [-1,1]) m.extrude(-5,4.8,s*(7.0+tier*.45),macTri(3.0),7+tier,MAC_COAT,s*.2); return m.build(); } function mdlMacSpinBeam(tier){ const m=MB(); tier=tier||1; macPad(m,20,tier,false); m.cyl(0,9.8,0,9.0,7.6,6.5,16,MAC_ARM_D); m.cyl(0,16.3,0,6.8,6.8,2.0,16,MAC_MECH); m.bevelBox(-3,18.3,0,17,7.5,13,1.2,MAC_ARM); tubeX(m,4.5,22.2,0,20+tier*3,2.7,1.25,14,MAC_BORE); for(const x of [4,10,16]) ringX(m,x,22.2,0,2.8,3.6,16,x===16?MAC_GLOW:MAC_TRIM); m.box(-6,25.9,0,5,.28,7,MAC_TEAM); macCore(m,-8,26,0,2.5,false); return m.build(); } function mdlMacPhaseDisruptor(tier){ const m=MB(); tier=tier||1; macPad(m,21,tier,false); m.extrude(0,9.8,0,macTri(12.5),9,MAC_ARM_D); for(let i=0;i<3;i++){ const a=-Math.PI/2+i*TAU/3,x=Math.cos(a)*7,z=Math.sin(a)*7; m.extrude(x,18,z,macTri(4.2),15+tier*2,MAC_ARM,a); m.box(x,23,z,1.0,8,.8,MAC_GLOW,a); } macCore(m,0,25+tier,0,4.2,false); for(const z of [-4.2,0,4.2]){ tubeX(m,5.0,27,z,13+tier*2,1.45,.68,12,MAC_BORE); ringX(m,16+tier*2,27,z,1.55,2.15,12,MAC_GLOW); } return m.build(); } function mdlMacVoidLance(tier){ const m=MB(); tier=tier||1; macPad(m,22,tier,false); m.extrude(-4,9.8,0,macTri(14),10,MAC_ARM_D); m.bevelBox(-4,19.8,0,21,9,16,1.5,MAC_ARM); for(const s of [-1,1]){ m.extrude(-7,23,s*8.5,macTri(4),11,MAC_COAT,s*.25); m.box(-7,27,s*8.6,1,6,.6,MAC_GLOW); } tubeX(m,3.5,25,0,29+tier*4,3.4,1.35,16,MAC_BORE); for(const x of [4,12,20,28]) ringX(m,x,25,0,3.5,4.4,18,x===28?MAC_GLOW:MAC_TRIM); macCore(m,-10,30,0,3.0,false); return m.build(); } function mdlMacSwarmFabricator(tier){ const m=MB(); tier=tier||1; macPad(m,24,tier,false); m.bevelBox(-2,9.8,0,31,14,29,2.0,MAC_ARM_D); m.extrude(-5,23.8,0,macTri(15),5,MAC_ARM); const cells=tier===1?4:tier===2?6:8; for(let i=0;i>1,z=(i%2?1:-1)*6.5,y=18+row*4.4; tubeX(m,9.5,y,z,4.0,2.25,1.20,12,MAC_BORE); m.bevelBox(6.8,y-2.2,z,5.4,4.4,5.4,.55,MAC_MECH); } macPortal(m,-14,28,0,5.0,8.2); macCrown(m,31,12,3); return m.build(); } function mdlMacEnergyVortex(tier){ const m=MB(); tier=tier||1; macPad(m,23,tier,true); m.extrude(0,9.8,0,macHex(14),10,MAC_ARM_D); for(let i=0;i<3;i++) macPylon(m,-Math.PI/2+i*TAU/3,15,9,25,4.0,true); macPortal(m,0,29+tier,0,10+tier,14+tier); ringX(m,.2,29+tier,0,6.0+tier,8.2+tier,26,MAC_GLOW); m.sphere(0,29+tier,0,3.4+tier*.5,11,MAC_GLOW_HI,1,false); m.ring(0,20,0,12,15,30,MAC_COAT); return m.build(); } function mdlMacPulseArray(tier){ const m=MB(); tier=tier||1; macPad(m,22,tier,false); m.extrude(-3,9.8,0,macTri(14),9,MAC_ARM_D); m.bevelBox(-4,18.8,0,19,7.5,18,1.2,MAC_ARM); const n=tier===1?3:tier===2?5:7; for(let i=0;i1) for(let i=0;i<3;i++){ const a=i*TAU/3,x=Math.cos(a)*r*.76,z=Math.sin(a)*r*.76; m.box(x,y+2.25,z,r*.24,.32,r*.16,MAC_TRIM,a); } return m; } function mdlMacSpinBeamBase(tier){ const m=MB(); tier=tier||1; macPad(m,20,tier,false); m.cyl(0,9.8,0,9.0,7.6,6.2,16,MAC_ARM_D); macAimBearing(m,16.0,6.9,tier); for(const s of [-1,1]){ m.bevelBox(-7,10,s*12.3,8,6,4,.55,MAC_COAT); m.box(-7,15.8,s*12.35,4,.24,2.2,s>0?MAC_TEAM:MAC_GLOW); } return m.build(); } function mdlMacSpinBeamTur(tier){ const m=MB(); tier=tier||1; m.cyl(0,0,0,6.9,6.45,2.0,16,MAC_MECH); m.bevelBox(-3,2.0,0,17,7.5,13,1.2,MAC_ARM); macCheeks(m,-3,4.4,6.55,9,2.6,tier); m.bevelBox(-8.5,3.4,0,6.5,6.6,11,.8,MAC_COAT); tubeX(m,4.5,5.9,0,20+tier*3,2.7,1.25,14,MAC_BORE); for(const x of [4,10,16]) ringX(m,x,5.9,0,2.8,3.6,16,x===16?MAC_GLOW:MAC_TRIM); m.box(-6,9.4,0,5,.28,7,MAC_TEAM); macCore(m,-8,9.4,0,2.5,false); return m.build(); } /* The mining laser formerly reused Spin Beam verbatim. The extractor version has a single lens throat, calibration forks and a low field cradle: it reads as sustained industrial cutting rather than a sweeping anti-unit weapon. */ function mdlMacMiningBase(tier){ const m=MB();tier=tier||1;macPad(m,21,tier,true); m.extrude(0,9.8,0,macHex(12.5),6.2,MAC_ARM_D); for(const s of [-1,1]){ macPylon(m,s*Math.PI/2,13.5,9,11+tier,3.1,true); m.bevelBox(-6,10,s*(12.2+tier*.25),8.5,5.6,3.2,.52,MAC_COAT); m.box(-6,15.42,s*(13.83+tier*.25),4.2,.22,.48,s>0?MAC_STATUS:MAC_GLOW); } macAimBearing(m,16.1,7.2,tier); return m.build(); } function mdlMacMiningTur(tier){ const m=MB();tier=tier||1; m.cyl(0,0,0,7.3,6.7,1.8,18,MAC_MECH); m.bevelBox(-4,1.8,0,18,7.0,13,1.15,MAC_ARM_D); for(const s of [-1,1]){ m.extrude(-2,5.0,s*(6.7+tier*.22),macTri(2.9),8+tier,MAC_PANEL,s*.16); m.box(-2,7.8,s*(6.8+tier*.22),.65,4.0,.55,s>0?MAC_STATUS:MAC_TEAM); } const L=18+tier*2.5; tubeX(m,3.5,6.0,0,L,2.55+tier*.08,1.12+tier*.05,16,MAC_BORE); for(let k=0;k<3+tier;k++){ const x=5+k*(L-3)/(2+tier); ringX(m,x,6.0,0,2.75+tier*.08,3.45+tier*.08,18,k===2+tier?MAC_GLOW_HI:MAC_EDGE); } macCore(m,-8.2,8.8,0,2.7+tier*.15,false); return m.build(); } function mdlMacPhaseBase(tier){ const m=MB(); tier=tier||1; macPad(m,21,tier,false); m.extrude(0,9.8,0,macTri(12.5),6.5,MAC_ARM_D); for(let i=0;i<3;i++){ const a=-Math.PI/2+i*TAU/3,x=Math.cos(a)*10,z=Math.sin(a)*10; m.extrude(x,9.8,z,macTri(3.8),8.0+tier,MAC_ARM_D,a); m.box(x,13,z,.8,4.2,.65,MAC_GLOW,a); } macAimBearing(m,16.3,7.0,tier); return m.build(); } function mdlMacPhaseTur(tier){ const m=MB(); tier=tier||1; m.cyl(0,0,0,7.1,6.5,1.8,16,MAC_MECH); m.bevelBox(-3,1.8,0,18,7.0,15,1.15,MAC_ARM); macCheeks(m,-3,4.0,7.55,9.5,2.5,tier); for(const z of [-4.2,0,4.2]){ tubeX(m,5.0,6.5,z,13+tier*2,1.45,.68,12,MAC_BORE); ringX(m,16+tier*2,6.5,z,1.55,2.15,12,MAC_GLOW); } for(const s of [-1,1]) m.box(-5,8.5,s*5.4,4.2,.24,1.0,s>0?MAC_TEAM:MAC_GLOW); macCore(m,-8.0,9.0,0,2.4,false); return m.build(); } /* Plasma Charger is a paired capacitor weapon, not another Phase Disruptor. A visible suspended core feeds two short open emitters; the silhouette stays compact enough for its existing 54-unit plot at every upgrade tier. */ function mdlMacPlasmaBase(tier){ const m=MB();tier=tier||1;macPad(m,20,tier,true); m.extrude(0,9.8,0,macTri(11.5),6.0,MAC_ARM_D); for(let i=0;i<3;i++){ const a=-Math.PI/2+i*TAU/3,x=Math.cos(a)*11,z=Math.sin(a)*11; m.extrude(x,9.8,z,macTri(3.5),7+tier,MAC_COAT,a); m.sphere(x,16.2+tier,z,1.25+tier*.08,8,i===0?MAC_STATUS:MAC_GLOW,1,false); } macAimBearing(m,16.2,6.9,tier); return m.build(); } function mdlMacPlasmaTur(tier){ const m=MB();tier=tier||1; m.cyl(0,0,0,7.0,6.45,1.8,18,MAC_MECH); m.bevelBox(-4,1.8,0,17,7.1,14,1.1,MAC_ARM); macCore(m,-3.6,8.3,0,3.1+tier*.22,true); for(const s of [-1,1]){ const z=s*(3.15+tier*.12),L=15+tier*1.5; m.bevelBox(1.5,4.0,z,10+tier,3.1,2.5,.38,MAC_PANEL); tubeX(m,4.2,6.15,z,L,1.42+tier*.08,.67+tier*.04,12,MAC_BORE); ringX(m,9.0,6.15,z,1.58+tier*.08,2.10+tier*.09,14,s>0?MAC_STATUS:MAC_GLOW); ringX(m,4.2+L,6.15,z,1.60+tier*.08,2.28+tier*.09,14,MAC_GLOW_HI); } m.box(-7.2,5.0,0,3.4,5.8,8.5,MAC_COAT); return m.build(); } function mdlMacVoidBase(tier){ const m=MB(); tier=tier||1; macPad(m,22,tier,false); m.extrude(-4,9.8,0,macTri(14),7.5,MAC_ARM_D); for(const s of [-1,1]){ m.extrude(-7,10,s*10,macTri(4),8+tier,MAC_COAT,s*.25); m.box(-7,13,s*10,1,4,.6,MAC_GLOW); } macAimBearing(m,17.2,7.4,tier); return m.build(); } function mdlMacVoidTur(tier){ const m=MB(); tier=tier||1; m.cyl(0,0,0,7.5,6.9,2.0,18,MAC_MECH); m.bevelBox(-4,2,0,22,8.5,16,1.4,MAC_ARM); macCheeks(m,-4.5,4.8,8.05,11,2.8,tier); tubeX(m,3.5,6.3,0,29+tier*4,3.4,1.35,16,MAC_BORE); for(const x of [4,12,20,28]) ringX(m,x,6.3,0,3.5,4.4,18,x===28?MAC_GLOW:MAC_TRIM); for(const s of [-1,1]) m.box(-5,8.8,s*6.4,6,.25,1.0,s>0?MAC_TEAM:MAC_GLOW); macCore(m,-10,9.1,0,3.0,false); return m.build(); } function mdlMacPulseBase(tier){ const m=MB(); tier=tier||1; macPad(m,22,tier,false); m.extrude(-3,9.8,0,macTri(14),6.0,MAC_ARM_D); for(const s of [-1,1]) macPylon(m,s*Math.PI/2,15,9,12+tier,3.0,true); macAimBearing(m,15.8,7.1,tier); return m.build(); } function mdlMacPulseTur(tier){ const m=MB(); tier=tier||1; m.cyl(0,0,0,7.2,6.6,1.8,18,MAC_MECH); m.bevelBox(-4,1.8,0,19,7.5,18,1.2,MAC_ARM); macCheeks(m,-4,4.2,9.05,9.5,2.6,tier); const n=tier===1?3:tier===2?5:7; for(let i=0;i0?MAC_TEAM:MAC_GLOW); } macAimBearing(m,16.8,8.0,tier); return m.build(); } function mdlMacSwarmTur(tier){ const m=MB(); tier=tier||1; m.cyl(0,0,0,8.1,7.5,1.9,18,MAC_MECH); m.bevelBox(-2,1.9,0,24,10,24,1.6,MAC_ARM_D); m.extrude(-5,11.9,0,macTri(12),4,MAC_ARM); macCheeks(m,-5,5.0,12.05,10.5,3.0,tier); const cells=tier===1?4:tier===2?6:8; for(let i=0;i>1,z=(i%2?1:-1)*6.5,y=5.2+row*4.0; tubeX(m,9.5,y,z,4.0,2.25,1.20,12,MAC_BORE); m.bevelBox(6.8,y-2.2,z,5.4,4.4,5.4,.55,MAC_MECH); } for(const s of [-1,1]) m.box(-8,13,s*8,5,.24,1,s>0?MAC_TEAM:MAC_GLOW); return m.build(); } function mdlMacSingularityBase(tier){ const m=MB(); tier=tier||1; macPad(m,25,tier,true); for(let i=0;i<6;i++){ const a=i*TAU/6,x=Math.cos(a)*17,z=Math.sin(a)*17; m.extrude(x,9.8,z,macTri(3.8),9+tier,MAC_ARM_D,a); m.box(x,13,z,1,5,.65,MAC_GLOW,a); } m.tube(0,10,0,9.0,6.0,6.0,22,MAC_BORE); macAimBearing(m,16.0,8.4,tier); return m.build(); } function mdlMacSingularityTur(tier){ const m=MB(); tier=tier||1; m.cyl(0,0,0,8.5,7.8,2.0,20,MAC_MECH); m.bevelBox(-5,2.0,0,20,8.5,18,1.35,MAC_ARM); macCheeks(m,-5,4.7,9.05,10,2.8,tier); macCore(m,-4,9.5,0,5.2+tier*.5,true); tubeX(m,3.5,8.3,0,18+tier*3,3.7,1.45,18,MAC_BORE); for(const x of [5,12,19]) ringX(m,x,8.3,0,3.8,4.8,20,x===19?MAC_GLOW_HI:MAC_TRIM); for(const s of [-1,1]) m.extrude(-5,6,s*8.5,macTri(3.4),8+tier,MAC_COAT,s*.2); return m.build(); } function mdlMacSeafortBase(tier){ const m=MB();tier=tier||1; m.extrude(0,0.6,0,macHex(20),3.2,MAC_PAD); // hex pontoon, air gap m.extrude(0,3.8,0,macHex(17.5),1.4,MAC_PANEL); for(let i=0;i<6;i++){ const a=i*TAU/6,x=Math.cos(a)*16.2,z=Math.sin(a)*16.2; m.cyl(x,0.2,z,.85,.7,.7,10,MAC_MECH); m.ring(x,1.0,z,.62,1.05,12,MAC_GLOW); } m.extrude(0,5.2,0,macTri(12.5),8.5,MAC_ARM_D); for(const s of [-1,1]) macPylon(m,s*Math.PI/2,14,5.2,12+tier,3.2,true); macAimBearing(m,14.2,6.8,tier); return m.build(); } function mdlMacSeafortTur(tier){ const m=MB();tier=tier||1; m.cyl(0,0,0,6.8,6.3,1.8,16,MAC_MECH); m.bevelBox(-3.2,1.8,0,15,6.6,13.5,1.0,MAC_ARM); tubeX(m,3.0,5.8,0,13+tier*1.4,1.85,.82,12,MAC_BORE); ringX(m,14+tier*1.4,5.8,0,1.95,2.45,14,MAC_GLOW); for(const s of [-1,1]){ tubeX(m,2.4,8.4,s*2.9,11+tier,.95,.42,10,MAC_BORE); ringX(m,12+tier,8.4,s*2.9,1.05,1.45,10,s>0?MAC_STATUS:MAC_GLOW); } macCore(m,-6.4,7.6,0,2.4,false); return m.build(); } function mdlMacStormBase(tier){ const m=MB();tier=tier||1;macPad(m,19,tier,true); for(const s of [-1,1]){ m.extrude(-1,9.8,s*12.4,macTri(4.2),8+tier,MAC_COAT,s*.18); for(const x of [-6,1,8]){ m.cyl(x,9.8,s*12.4,1.15,.9,5.5+tier*.5,8,MAC_MECH); m.sphere(x,15.5+tier*.5,s*12.4,.72,7,MAC_GLOW,1,false); } } macCore(m,0,18.2,0,3.4+tier*.2,true); macAimBearing(m,20.4,7.0,tier); return m.build(); } function mdlMacStormTur(tier){ const m=MB();tier=tier||1; m.cyl(0,0,0,7.2,6.6,1.8,16,MAC_MECH); m.bevelBox(-2.6,1.8,0,16,6.8,15,.95,MAC_ARM_D); for(let r=0;r<4;r++) for(let c=0;c<4;c++){ const y=4.0+(r-1.5)*1.95,z=(c-1.5)*2.95; tubeX(m,4.8,y,z,2.1,1.05,.62,8,MAC_BORE); m.bevelBox(3.4,y-1.0,z,3.0,2.0,2.2,.24,MAC_MECH); } macCore(m,-7.2,7.4,0,2.6,false); return m.build(); } /* The runtime may select this map by faction without teaching the model module about simulation objects. Directed defenses pair a foundation here with a +X tracking assembly in BLD_TUR_MDL_MACHINE; field/support devices stay complete base meshes because they act radially rather than aim at a unit. */ var BLD_MDL_MACHINE={ mex:mdlMacMex, pgen:mdlMacPgen, fac:mdlMacFac, turret:mdlMacPhaseBase, bunker:mdlMacPulseBase, sgen:mdlMacShield, tgate:mdlMacTargetGate, nest:mdlMacRelayNest, harbor:mdlMacHarbor, bastion:mdlMacGravityBase, techlab:mdlMacTechlab, aatower:mdlMacAABase, airfield:mdlMacAirfield, uplink:mdlMacUplink, hq:mdlMacHQ, hellstorm:mdlMacSpinBeamBase, arc:mdlMacEnergyVortex, rail:mdlMacVoidBase, nova:mdlMacSingularityBase, wall:mdlMacWall, minelaser:mdlMacMiningBase, missilebastion:mdlMacSwarmBase, plasma:mdlMacPlasmaBase, gate:mdlMacGate, geo:mdlMacGeo, silo:mdlMacSilo, fab:mdlMacFab, seafort:mdlMacSeafortBase, stormcaller:mdlMacStormBase, gravitywell:mdlMacGravityBase, spinbeam:mdlMacSpinBeamBase, phasedisruptor:mdlMacPhaseBase, voidlance:mdlMacVoidBase, swarmfabricator:mdlMacSwarmBase, energyvortex:mdlMacEnergyVortex, pulsearray:mdlMacPulseBase, singularitycore:mdlMacSingularityBase, }; /* Stage S1 — isolated Syndicate landmark packs. The Machine kit deliberately keeps this data beside its builders instead of recolouring the generic renderer: each landmark can receive an authored BaseAO/NRE/mask triplet later without changing another building. These are semantic-bake prototypes only — maps:null is an explicit record that no UV-authored texture set is being claimed yet. */ const SYN_MACHINE_STRUCTURE_PACKS=Object.freeze({ hq:Object.freeze({ id:'syndicate-hq-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_GOLD }) }), fac:Object.freeze({ id:'syndicate-fac-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), techlab:Object.freeze({ id:'syndicate-techlab-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_GOLD }) }), pgen:Object.freeze({ id:'syndicate-pgen-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_GOLD }) }), mex:Object.freeze({ id:'syndicate-mex-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_NANO, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), geo:Object.freeze({ id:'syndicate-geo-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), airfield:Object.freeze({ id:'syndicate-airfield-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), rail:Object.freeze({ id:'syndicate-rail-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), uplink:Object.freeze({ id:'syndicate-uplink-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), turret:Object.freeze({ id:'syndicate-turret-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), bunker:Object.freeze({ id:'syndicate-bunker-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), bastion:Object.freeze({ id:'syndicate-bastion-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), aatower:Object.freeze({ id:'syndicate-aatower-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), minelaser:Object.freeze({ id:'syndicate-minelaser-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), missilebastion:Object.freeze({ id:'syndicate-missilebastion-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), hellstorm:Object.freeze({ id:'syndicate-hellstorm-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), seafort:Object.freeze({ id:'syndicate-seafort-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), stormcaller:Object.freeze({ id:'syndicate-stormcaller-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), arc:Object.freeze({ id:'syndicate-arc-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), sgen:Object.freeze({ id:'syndicate-sgen-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), plasma:Object.freeze({ id:'syndicate-plasma-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), wall:Object.freeze({ id:'syndicate-wall-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), gate:Object.freeze({ id:'syndicate-gate-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), nest:Object.freeze({ id:'syndicate-nest-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_GOLD }) }), harbor:Object.freeze({ id:'syndicate-harbor-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), tgate:Object.freeze({ id:'syndicate-tgate-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), silo:Object.freeze({ id:'syndicate-silo-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), fab:Object.freeze({ id:'syndicate-fab-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }), nova:Object.freeze({ id:'syndicate-nova-v2',source:'semantic-bake', maps:null, surfaces:Object.freeze({ [MAT.TWR_ARMOR]:MAT.SYN_NANO,[MAT.TWR_COAT]:MAT.SYN_HOLO, [MAT.TWR_MACH]:MAT.SYN_GOLD,[MAT.TWR_GLOW]:MAT.SYN_CONDUIT, [MAT.TWR_PAD]:MAT.SYN_HOLO,[MAT.TRIM]:MAT.SYN_NANO }) }) }); function synMachineStructureSurfacePass(geo,pack){ if(!geo||!geo.v||!pack)return geo; const v=geo.v; for(let o=11;o({base:()=>mdlMacGravityBase(t),tur:()=>mdlMacGravityTur(t)})), spinbeam:[1,2,3].map(t=>({base:()=>mdlMacSpinBeamBase(t),tur:()=>mdlMacSpinBeamTur(t)})), phasedisruptor:[1,2,3].map(t=>({base:()=>mdlMacPhaseBase(t),tur:()=>mdlMacPhaseTur(t)})), voidlance:[1,2,3].map(t=>({base:()=>mdlMacVoidBase(t),tur:()=>mdlMacVoidTur(t)})), swarmfabricator:[1,2,3].map(t=>({base:()=>mdlMacSwarmBase(t),tur:()=>mdlMacSwarmTur(t)})), energyvortex:[1,2,3].map(t=>({base:()=>mdlMacEnergyVortex(t)})), pulsearray:[1,2,3].map(t=>({base:()=>mdlMacPulseBase(t),tur:()=>mdlMacPulseTur(t)})), singularitycore:[1,2,3].map(t=>({base:()=>mdlMacSingularityBase(t),tur:()=>mdlMacSingularityTur(t)})), aatower:[1,2,3].map(t=>({base:()=>mdlMacAABase(t),tur:()=>mdlMacAATur(t)})), minelaser:[1,2,3].map(t=>({base:()=>mdlMacMiningBase(t),tur:()=>mdlMacMiningTur(t)})), plasma:[1,2,3].map(t=>({base:()=>mdlMacPlasmaBase(t),tur:()=>mdlMacPlasmaTur(t)})), seafort:[1,2,3].map(t=>({base:()=>mdlMacSeafortBase(t),tur:()=>mdlMacSeafortTur(t)})), stormcaller:[1,2,3].map(t=>({base:()=>mdlMacStormBase(t),tur:()=>mdlMacStormTur(t)})), }; /* Runtime type aliases keep the simulation/save vocabulary stable while the visible Mk1/Mk2/Mk3 geometry follows the Machine contact-sheet archetype. */ for(const pair of [ ['turret','phasedisruptor'],['bunker','pulsearray'],['bastion','gravitywell'], ['hellstorm','spinbeam'],['arc','energyvortex'], ['rail','voidlance'],['nova','singularitycore'], ['missilebastion','swarmfabricator'] ]) BLD_TIER_MDL_MACHINE[pair[0]]=BLD_TIER_MDL_MACHINE[pair[1]]; for(const k in BLD_TIER_MDL_MACHINE){ const pk=k==='phasedisruptor'?'turret':k==='pulsearray'?'bunker':k==='gravitywell'?'bastion':k==='spinbeam'?'hellstorm':k==='energyvortex'?'arc':k==='voidlance'?'rail':k==='singularitycore'?'hellstorm':k==='swarmfabricator'?'missilebastion':k; if(SYN_MACHINE_STRUCTURE_PACKS[pk]){ BLD_TIER_MDL_MACHINE[k]=BLD_TIER_MDL_MACHINE[k].map(V=>({ base:synMachineStructureFactory(V.base,pk), tur:V.tur?synMachineStructureFactory(V.tur,pk):null })); } }