/* Concatenator leftover `;;` lived here; do not restore it. */ /* ============================================================================ INFESTATION SWARM - PROCEDURAL STRUCTURE LIBRARY ---------------------------------------------------------------------------- Load after engine/models.js. These are complete one-piece organic buildings, not skins over Terran bases. Their silhouette vocabulary is rooted creep, asymmetrical chitin, wet tissue, egg sacs, bone tools and genuinely hollow mouths. Low radial segment counts keep the full faction practical on phones. This module intentionally has no runtime takeover. Integration can choose BLD_MDL_INFESTATION without making this optional art package own faction or renderer policy. Keeping every helper inside the closure also protects the game's single classic-script global scope from another name collision. ============================================================================ */ var BLD_MDL_INFESTATION, BLD_TUR_MDL_INFESTATION, BLD_TIER_MDL_INFESTATION, BLD_TUR_H_INFESTATION, BLD_TUR_S_INFESTATION; /* Ichor RGB — same wet green as INF_MUCUS / INF_SAC / INF_GLOW inside the IIFE. organicfx.js prefers this for caste-0 infestation so a nest and a Ravager bleed the same substance the sac tiles are painted with. */ var INF_ICHOR=Object.freeze({ wet:[115,177,77], dark:[62,88,30], hi:[185,255,72] }); (function(){ /* Existing atlas cells are deliberately zoned by biological function. Using one CHITIN tile for everything recreated the noisy single-material look this faction pass is meant to replace. */ const INF_CHITIN=C(118,78,58), INF_CHITIN_H=C(166,116,76); const INF_FLESH=C(119,56,68), INF_FLESH_H=C(174,84,91); const INF_SAC=C(126,151,65), INF_MUCUS=C(115,177,77); const INF_GLOW=C(185,255,72), INF_GLOW_H=C(226,255,151); const INF_ROOT=C(58,43,34), INF_BONE=C(219,198,151); const INF_SILK=C(191,184,169), INF_BORE=C(12,8,10); COL_MAT.set(INF_CHITIN,MAT.CHITIN); COL_MAT.set(INF_CHITIN_H,MAT.CHITIN); COL_MAT.set(INF_FLESH,MAT.RUST); COL_MAT.set(INF_FLESH_H,MAT.LEAF); COL_MAT.set(INF_SAC,MAT.GLASS); COL_MAT.set(INF_MUCUS,MAT.CRYST); /* TWR_GLOW's atlas tile is Nova cyan (#78b6c4). Brood lumen painted through that id read as Frontline energy on every hive, nest and glow node. Slime keeps the wet-green emissive the ichor VFX already uses. */ COL_MAT.set(INF_GLOW,MAT.BROOD_SLIME);COL_MAT.set(INF_GLOW_H,MAT.BROOD_SLIME); COL_MAT.set(INF_ROOT,MAT.EARTH); COL_MAT.set(INF_BONE,MAT.STONE); COL_MAT.set(INF_SILK,MAT.TRIM); COL_MAT.set(INF_BORE,MAT.TWR_BORE); function infRand(seed){ let s=(seed|0)||1; return function(){ s=(s*1664525+1013904223)>>>0; return s/4294967296; }; } function infMix(a,b,t){ return a+(b-a)*t; } function infPoint(a,b,t){ return [infMix(a[0],b[0],t),infMix(a[1],b[1],t),infMix(a[2],b[2],t)]; } /* Rotate a temporary +Y primitive onto the line a->b. Positions and normals use the same orthonormal frame; UV and material data remain untouched. */ function infMergeAlong(m,mm,a,b){ let dx=b[0]-a[0],dy=b[1]-a[1],dz=b[2]-a[2]; const len=Math.hypot(dx,dy,dz)||1; dx/=len;dy/=len;dz/=len; const rx=Math.abs(dy)>.92?0:0, ry=Math.abs(dy)>.92?0:1, rz=Math.abs(dy)>.92?1:0; let ux=ry*dz-rz*dy,uy=rz*dx-rx*dz,uz=rx*dy-ry*dx; const ul=Math.hypot(ux,uy,uz)||1;ux/=ul;uy/=ul;uz/=ul; const wx=uy*dz-uz*dy,wy=uz*dx-ux*dz,wz=ux*dy-uy*dx; for(let i=0;i1&&i%2===0){ const s=a+(i%4<2?.34:-.34),p3=[Math.cos(s)*reach*.88,.22,Math.sin(s)*reach*.88]; infLimb(m,p1,p3,r*.052,r*.012,INF_FLESH,6,true); } } const lobes=3+Math.min(t,2); for(let i=0;i0?INF_SAC:INF_FLESH_H,.95); infBulb(m,-2,10,s*16,4.0,INF_MUCUS,.82); infLimb(m,[-8,14,s*10],[-2,22,s*15],2.4,.7,INF_CHITIN,7,true); } infGlowNode(m,-6,20,0,2.4); return m.build(); } function mdlInfShield(){ const m=MB();infRoots(m,22,9,961,2);infMound(m,0,4.6,0,12,967,1); infBulb(m,0,12,0,7.5,INF_MUCUS,1.12);m.ring(0,19.8,0,7.5,10.5,24,INF_GLOW); for(let i=0;i<6;i++){ const a=i*TAU/6,p0=[Math.cos(a)*15,4,Math.sin(a)*15],p1=[Math.cos(a)*10,24,Math.sin(a)*10],p2=[0,31,0]; infLimb(m,p0,p1,2.0,.8,INF_CHITIN,7,true);infLimb(m,p1,p2,.82,.18,INF_SILK,6,true); } infGlowNode(m,0,12,0,3.0);return m.build(); } function mdlInfTransitGate(){ const m=MB();infRoots(m,31,10,981,2);infMound(m,-18,4.6,0,11,987,1);infMound(m,18,4.6,0,11,991,1); const left=[[-19,7,0],[-21,25,0],[-10,41,0],[0,46,0]],right=[[19,7,0],[21,25,0],[10,41,0],[0,46,0]]; for(const path of [left,right])for(let i=0;i20?INF_GLOW:INF_BONE); infGlowNode(m,-7,18,0,2.3);return m.build(); } function mdlInfWall(){ const m=MB(); for(let i=-3;i<=3;i++){ const x=i*5.2,h=11+(i%2===0?5:0); infLimb(m,[x,0,-6],[x+(i%2)*2,h,0],2.5,1.25,i%2?INF_ROOT:INF_CHITIN,7,true); infSpike(m,[x,h*.55,0],[x,h+8,-(i%3-1)*4],1.1,false); if(i<3){ infLimb(m,[x,5,0],[x+5.2,5.8,0],1.05,.82,INF_FLESH,6,true); infLimb(m,[x,h*.55,0],[x+5.2,9,0],.75,.48,INF_SILK,6,true); } } m.box(0,0,0,35,2.2,14,INF_ROOT);m.ring(0,2.3,0,8,15,18,INF_GLOW);return m.build(); } function mdlInfProboscis(){ const m=MB();infRoots(m,20,8,1141,2);infMound(m,-4,4.6,0,12,1147,1); infOpenLimb(m,[-5,12,0],[27,17,0],4.2,1.55,9); for(let i=0;i<4;i++){ const x=2+i*6;ringX(m,x,13.1+x*.15,0,1.9-i*.08,2.7-i*.08,14,i===3?INF_GLOW:INF_CHITIN_H); } for(const s of [-1,1])infSpike(m,[-3,9,s*5],[10,17,s*8],1.1,false); infGlowNode(m,-6,13,0,2.2);return m.build(); } function mdlInfPlasma(){ const m=MB();infRoots(m,21,9,1161,2);infMound(m,0,4.6,0,12,1167,2); for(let i=0;i<5;i++){ const a=i*TAU/5,rad=8+(i%2)*2;infBulb(m,Math.cos(a)*rad,9+(i%2)*3,Math.sin(a)*rad,3.4,INF_MUCUS,.95); infLimb(m,[0,9,0],[Math.cos(a)*rad,11+(i%2)*3,Math.sin(a)*rad],1.0,.42,INF_FLESH_H,6,true); } m.tube(0,11,0,5.0,2.5,3.5,12,INF_BORE);infGlowNode(m,0,14,0,3.3); infCrownSpikes(m,0,10,0,9,5,12,1171);return m.build(); } function mdlInfGate(){ const m=MB();m.box(0,0,0,43,2.2,17,INF_ROOT); for(const s of [-1,1]){ infMound(m,s*16,2.2,0,9,1191+s,1); infLimb(m,[s*16,5,0],[s*18,23,0],4.3,2.8,INF_CHITIN,8,true); infLimb(m,[s*18,23,0],[0,33,0],2.9,.65,INF_BONE,7,true); infGlowNode(m,s*16,12,0,1.8); } ringX(m,.1,20,0,8.5,10.3,22,INF_SILK);return m.build(); } function mdlInfGeo(){ const m=MB();infRoots(m,23,9,1211,2);infMound(m,0,4.6,0,13,1217,2); const cells=[[-7,-5],[7,-5],[-7,6],[7,6]]; for(let i=0;i1) for(const s of [-1,1]) infSpike(m,[-r*.3,2,s*r*.55],[-r*.9,6+t,s*r*.95],r*.18,false); return m; } function mdlInfSpineBase(tier){ const t=tier||1,m=MB(),r=17+t*2; infRoots(m,r,7+t,1401+t,t);infMound(m,-2,4.6,0,r*.58,1407+t,t); infTrunk(m,-2,5,0,6.2+t*.5,9,1413+t,t);infAimSocket(m,16,4.5+t*.25,t); for(let i=0;i<4+t;i++){ const a=i/(4+t)*TAU,base=[Math.cos(a)*8,7,Math.sin(a)*8]; infSpike(m,base,[Math.cos(a)*(14+t),13+(i%2)*3,Math.sin(a)*(14+t)],1.25+t*.08,i%2===0); } infGlowNode(m,-4,11,0,1.8+t*.12);return m.build(); } function mdlInfSpineTur(tier){ const t=tier||1,m=MB();infTurJoint(m,4.4+t*.25,t); infOpenLimb(m,[-1,2,0],[13+t*3,9+t*1.5,0],4.1+t*.35,2.2+t*.18,9); for(const s of [-1,1]) infSpike(m,[1,3,s*3.0],[11+t*2,10+t,s*(5+t*.4)],1.2+t*.10,true); infGlowNode(m,-3,3.8,0,1.8+t*.16);return m.build(); } /* Concussion Mortar used to be the Sentinel spine family at a different label. Its new siege organ stores pressure in rear sacs, braces against recoil with bone outriggers, and raises one wide lobbed-fire throat. */ function mdlInfMortarBase(tier){ const t=tier||1,m=MB(),r=18+t*1.5; infRoots(m,r,8+t,1421+t,t);infMound(m,-3,4.6,0,r*.62,1427+t,t); infTrunk(m,-6,5,0,6.5+t*.45,10+t,1433+t,t);infAimSocket(m,16.0,4.8+t*.22,t); for(const s of [-1,1]){ infBulb(m,-9,8.0,s*(6.2+t*.45),3.5+t*.28,s>0?INF_SAC:INF_MUCUS,.90); infLimb(m,[-7,7,s*4],[-13,2,s*(10+t)],1.45+t*.08,.45,INF_ROOT,7,true); infSpike(m,[-3,8,s*5],[6,13,s*(10+t*.45)],1.15+t*.07,true); } infGlowNode(m,-7,12,0,2.0+t*.12);return m.build(); } function mdlInfMortarTur(tier){ const t=tier||1,m=MB();infTurJoint(m,4.8+t*.22,t); infBulb(m,-5,3.0,0,4.0+t*.34,INF_SAC,.94); infOpenLimb(m,[-2,2,0],[11+t*2,13+t*1.8,0],5.1+t*.34,2.65+t*.19,10); for(const s of [-1,1]){ infLimb(m,[-2,3,s*2.8],[7+t,8+t*.7,s*(5.8+t*.45)],1.25,.62,INF_FLESH_H,7,true); infSpike(m,[-4,4,s*3.5],[4+t,10+t,s*(8+t*.5)],1.0+t*.07,true); } infCrownSpikes(m,-4,4,0,4.6,3+t,6+t,1437+t); infGlowNode(m,-5,5,0,2.2+t*.14);return m.build(); } function mdlInfThornBase(tier){ const t=tier||1,m=MB(),r=20+t*2; infRoots(m,r,9+t,1441+t,t);infMound(m,-1,4.6,0,r*.67,1447+t,t); infTrunk(m,-3,5,0,5.8+t*.4,6.5,1453+t,t);infAimSocket(m,13,4.4+t*.22,t); const n=5+t; for(let i=0;i19?INF_GLOW:INF_BONE); infGlowNode(m,-4,4,0,2.1+t*.12);return m.build(); } function mdlInfAcidBase(tier){ const t=tier||1,m=MB(),r=18+t*2; infRoots(m,r,8,1601+t,t);infMound(m,0,4.6,0,r*.64,1607+t,t); m.cyl(0,7,0,8+t,6+t*.7,3.2,10,INF_CHITIN,false);infAimSocket(m,11.2,5.3+t*.3,t); for(let i=0;i<3+t;i++){ const a=(i+.5)/(3+t)*TAU;infBulb(m,Math.cos(a)*9,7,Math.sin(a)*9,2.4+t*.2,INF_MUCUS,.8); } return m.build(); } function mdlInfAcidTur(tier){ const t=tier||1,m=MB();infTurJoint(m,5.3+t*.3,t); infOpenLimb(m,[-1,2,0],[11+t*2,6+t,0],4.8+t*.35,2.6+t*.22,10); infBulb(m,-4,2,0,3.2+t*.25,INF_MUCUS,.94); for(const s of [-1,1]) infSpike(m,[0,3,s*3.4],[8+t,8+t,s*(6+t*.4)],1.0+t*.07,false); infGlowNode(m,-3,3,0,2.1+t*.16);return m.build(); } function mdlInfProboscisBase(tier){ const t=tier||1,m=MB(),r=19+t*1.5; infRoots(m,r,8,1641+t,t);infMound(m,-4,4.6,0,12+t*.6,1647+t,t); infTrunk(m,-5,5,0,5.8+t*.35,6.5,1653+t,t);infAimSocket(m,13,4.2+t*.22,t); return m.build(); } function mdlInfProboscisTur(tier){ const t=tier||1,m=MB();infTurJoint(m,4.2+t*.22,t); infOpenLimb(m,[-1,2,0],[25+t*3,6+t,0],4.2+t*.2,1.55+t*.12,9); for(let x=3;x<23+t*2;x+=6) ringX(m,x,4.6+x*.04,0,1.9,2.7,14,x>18?INF_GLOW:INF_CHITIN_H); for(const s of [-1,1]) infSpike(m,[-2,2,s*3.5],[10+t*2,7,s*(7+t*.4)],1.0,false); infGlowNode(m,-3,3,0,1.8+t*.14);return m.build(); } function mdlInfPlasmaBase(tier){ const t=tier||1,m=MB(),r=20+t*1.5; infRoots(m,r,9,1681+t,t);infMound(m,0,4.6,0,12+t*.6,1687+t,t); for(let i=0;i<4+t;i++){ const a=i/(4+t)*TAU,rad=8+(i%2)*2;infBulb(m,Math.cos(a)*rad,8,Math.sin(a)*rad,2.8+t*.18,INF_MUCUS,.95); infLimb(m,[0,8,0],[Math.cos(a)*rad,10,Math.sin(a)*rad],.85,.34,INF_FLESH_H,6,true); } infAimSocket(m,12.5,5.0+t*.25,t);return m.build(); } function mdlInfPlasmaTur(tier){ const t=tier||1,m=MB();infTurJoint(m,5.0+t*.25,t); infBulb(m,-3,3,0,3.8+t*.3,INF_MUCUS,1.0); infOpenLimb(m,[0,2,0],[13+t*2,7+t,0],4.4+t*.25,2.5+t*.18,10); for(const s of [-1,1]) infSpike(m,[-2,3,s*3.6],[9+t,8+t,s*(6+t*.5)],1.0+t*.08,false); infGlowNode(m,-3,4,0,2.7+t*.2);return m.build(); } function mdlInfSeafortBase(tier){ const t=tier||1,m=MB(),r=18+t; infMound(m,0,2.2,0,r*.72,1601+t,t); infTrunk(m,-4,4,0,6.2+t*.3,8+t,1607+t,t);infAimSocket(m,14.8,4.6+t*.2,t); for(const s of [-1,1]){ infOpenLimb(m,[-8,6,s*6],[16,8,s*(14+t)],4.2+t*.2,2.2,8); infBulb(m,-10,7,s*(8+t*.3),3.2+t*.2,s>0?INF_SAC:INF_MUCUS,.88); } infGlowNode(m,-6,11,0,2.1+t*.12);return m.build(); } function mdlInfSeafortTur(tier){ const t=tier||1,m=MB();infTurJoint(m,4.6+t*.2,t); infOpenLimb(m,[-1,2,0],[12+t*2,8+t,0],4.6+t*.28,2.4+t*.16,9); for(const s of [-1,1]) infOpenLimb(m,[0,4,s*2],[10+t,10+t,s*(4+t*.3)],2.6+t*.14,1.3,7); infGlowNode(m,-3,4,0,1.9+t*.14);return m.build(); } function mdlInfStormBase(tier){ const t=tier||1,m=MB(),r=17+t*1.2; infRoots(m,r,8+t,1621+t,t);infMound(m,-2,4.6,0,r*.62,1627+t,t); infTrunk(m,-5,5,0,6.0+t*.4,8+t,1633+t,t);infAimSocket(m,15.4,4.7+t*.2,t); for(let i=0;i<6;i++){ const a=i/6*TAU;infBulb(m,Math.cos(a)*9,9+(i%2)*2,Math.sin(a)*9,2.8+t*.16,i%2?INF_SAC:INF_MUCUS,.9); } infGlowNode(m,0,16,0,2.6+t*.16);return m.build(); } function mdlInfStormTur(tier){ const t=tier||1,m=MB();infTurJoint(m,4.7+t*.2,t); for(let r=0;r<4;r++) for(let c=0;c<4;c++){ const y=3.6+(r-1.5)*1.7,z=(c-1.5)*2.6; infOpenLimb(m,[-1,2,z*.4],[10+t,y,z],2.2+t*.1,1.15,6); } infGlowNode(m,-3,3.6,0,2.0+t*.12);return m.build(); } /* Every simulation key receives its own wrapper even when it shares an art family. That keeps old saves stable and gives balance/art tuning an escape hatch without renaming a building later. */ BLD_MDL_INFESTATION={ mex:()=>mdlInfMex(), pgen:()=>mdlInfPgen(), fac:()=>mdlInfFactory(), turret:()=>mdlInfSpineBase(1), bunker:()=>mdlInfThornBase(1), sgen:()=>mdlInfShield(), tgate:()=>mdlInfTransitGate(), nest:()=>mdlInfThornNest(2), harbor:()=>mdlInfHarbor(), bastion:()=>mdlInfMortarBase(1), techlab:()=>mdlInfTech(), aatower:()=>mdlInfSporeBase(1), airfield:()=>mdlInfAirfield(), uplink:()=>mdlInfSonicShrieker(2), hq:()=>mdlInfBroodSpire(3), hellstorm:()=>mdlInfToxicBase(2), arc:()=>mdlInfArc(), rail:()=>mdlInfBoneBase(1), nova:()=>mdlInfAcidBase(3), wall:()=>mdlInfWall(), minelaser:()=>mdlInfProboscisBase(1), missilebastion:()=>mdlInfMissileBase(1), plasma:()=>mdlInfPlasmaBase(1), gate:()=>mdlInfGate(), geo:()=>mdlInfGeo(), silo:()=>mdlInfSilo(), fab:()=>mdlInfFab(), seafort:()=>mdlInfSeafortBase(1), stormcaller:()=>mdlInfStormBase(1), spinespiker:mdlInfSpineBase, gorespiker:mdlInfSpineBase, spineburrow:mdlInfSpineBase, toxicgusher:mdlInfToxicBase, acidgusher:mdlInfToxicBase, toxicspewer:mdlInfToxicBase, sporelauncher:mdlInfSporeBase, sporetower:mdlInfSporeBase, silktrap:mdlInfSilkTrap, tendriltrap:mdlInfSilkTrap, tendrilmaw:mdlInfSilkTrap, acidgeyser:mdlInfAcidBase, creeppustule:mdlInfAcidBase, thornnest:mdlInfThornBase, raptornest:mdlInfThornBase, sonicshrieker:mdlInfSonicShrieker, broodspire:mdlInfBroodSpire, broodchamber:mdlInfBroodSpire, }; BLD_TUR_MDL_INFESTATION={ turret:mdlInfSpineTur,bunker:mdlInfThornTur,bastion:mdlInfMortarTur, aatower:mdlInfSporeTur,hellstorm:mdlInfToxicTur,rail:mdlInfBoneTur, nova:mdlInfAcidTur,minelaser:mdlInfProboscisTur, missilebastion:mdlInfMissileTur,plasma:mdlInfPlasmaTur, seafort:mdlInfSeafortTur,stormcaller:mdlInfStormTur, spinespiker:mdlInfSpineTur,gorespiker:mdlInfSpineTur,spineburrow:mdlInfSpineTur, toxicgusher:mdlInfToxicTur,acidgusher:mdlInfToxicTur,toxicspewer:mdlInfToxicTur, sporelauncher:mdlInfSporeTur,sporetower:mdlInfSporeTur, acidgeyser:mdlInfAcidTur,creeppustule:mdlInfAcidTur, thornnest:mdlInfThornTur,raptornest:mdlInfThornTur, }; BLD_TUR_H_INFESTATION={ turret:17.25,bunker:14.25,bastion:17.25,aatower:17.75,hellstorm:18.75, rail:18.25,nova:12.45,minelaser:14.25,missilebastion:16.45,plasma:13.75, seafort:16.05,stormcaller:16.65, spinespiker:17.25,gorespiker:17.25,spineburrow:17.25, toxicgusher:18.75,acidgusher:18.75,toxicspewer:18.75, sporelauncher:17.75,sporetower:17.75,acidgeyser:12.45,creeppustule:12.45, thornnest:14.25,raptornest:14.25, }; BLD_TUR_S_INFESTATION={ turret:1.08,bunker:1.05,bastion:1.04,aatower:1.05,hellstorm:1.06, rail:1.08,nova:1.08,minelaser:1.07,missilebastion:1.04,plasma:1.07, seafort:1.06,stormcaller:1.05, spinespiker:1.08,gorespiker:1.08,spineburrow:1.08, toxicgusher:1.06,acidgusher:1.06,toxicspewer:1.06, sporelauncher:1.05,sporetower:1.05,acidgeyser:1.08,creeppustule:1.08, thornnest:1.05,raptornest:1.05, }; const tiered={ spinespiker:[mdlInfSpineBase,mdlInfSpineTur],gorespiker:[mdlInfSpineBase,mdlInfSpineTur], spineburrow:[mdlInfSpineBase,mdlInfSpineTur], toxicgusher:[mdlInfToxicBase,mdlInfToxicTur],acidgusher:[mdlInfToxicBase,mdlInfToxicTur], toxicspewer:[mdlInfToxicBase,mdlInfToxicTur], sporelauncher:[mdlInfSporeBase,mdlInfSporeTur],sporetower:[mdlInfSporeBase,mdlInfSporeTur], silktrap:[mdlInfSilkTrap,null],acidgeyser:[mdlInfAcidBase,mdlInfAcidTur], creeppustule:[mdlInfAcidBase,mdlInfAcidTur],thornnest:[mdlInfThornBase,mdlInfThornTur], raptornest:[mdlInfThornBase,mdlInfThornTur], sonicshrieker:[mdlInfSonicShrieker,null],broodspire:[mdlInfBroodSpire,null], turret:[mdlInfSpineBase,mdlInfSpineTur],bunker:[mdlInfThornBase,mdlInfThornTur], bastion:[mdlInfMortarBase,mdlInfMortarTur],aatower:[mdlInfSporeBase,mdlInfSporeTur], uplink:[mdlInfSonicShrieker,null],hellstorm:[mdlInfToxicBase,mdlInfToxicTur], rail:[mdlInfBoneBase,mdlInfBoneTur],nova:[mdlInfAcidBase,mdlInfAcidTur], minelaser:[mdlInfProboscisBase,mdlInfProboscisTur], missilebastion:[mdlInfMissileBase,mdlInfMissileTur],plasma:[mdlInfPlasmaBase,mdlInfPlasmaTur], seafort:[mdlInfSeafortBase,mdlInfSeafortTur],stormcaller:[mdlInfStormBase,mdlInfStormTur], }; BLD_TIER_MDL_INFESTATION={}; for(const k in tiered){ const pair=tiered[k],base=pair[0],tur=pair[1]; BLD_TIER_MDL_INFESTATION[k]=[1,2,3].map(t=>({base:()=>base(t),tur:tur?()=>tur(t):null})); } const INF_BLD_BESPOKE_PACKS=Object.freeze({ nest: Object.freeze({id:'brood-nest-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), hq: Object.freeze({id:'brood-hive-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), fac: Object.freeze({id:'brood-hive-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), harbor: Object.freeze({id:'brood-hive-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), seafort: Object.freeze({id:'brood-hive-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), stormcaller: Object.freeze({id:'brood-spore-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), airfield: Object.freeze({id:'brood-hive-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), tgate: Object.freeze({id:'brood-hive-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), spire: Object.freeze({id:'brood-spire-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), broodspire: Object.freeze({id:'brood-spire-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), broodchamber: Object.freeze({id:'brood-spire-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), techlab: Object.freeze({id:'brood-spire-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), aatower: Object.freeze({id:'brood-spore-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), sporelauncher: Object.freeze({id:'brood-spore-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), sporetower: Object.freeze({id:'brood-spore-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), missilebastion: Object.freeze({id:'brood-spore-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), wall: Object.freeze({id:'brood-carapace-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), gate: Object.freeze({id:'brood-carapace-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), bunker: Object.freeze({id:'brood-carapace-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), bastion: Object.freeze({id:'brood-carapace-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), rail: Object.freeze({id:'brood-carapace-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), arc: Object.freeze({id:'brood-carapace-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), nova: Object.freeze({id:'brood-carapace-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), plasma: Object.freeze({id:'brood-carapace-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), minelaser: Object.freeze({id:'brood-carapace-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), mex: Object.freeze({id:'brood-sac-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), pgen: Object.freeze({id:'brood-sac-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), geo: Object.freeze({id:'brood-sac-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), silo: Object.freeze({id:'brood-sac-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), fab: Object.freeze({id:'brood-sac-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), acidgeyser: Object.freeze({id:'brood-sac-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), creeppustule: Object.freeze({id:'brood-sac-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), toxicgusher: Object.freeze({id:'brood-sac-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), acidgusher: Object.freeze({id:'brood-sac-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), toxicspewer: Object.freeze({id:'brood-sac-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), hellstorm: Object.freeze({id:'brood-sac-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), turret: Object.freeze({id:'brood-mound-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), spinespiker: Object.freeze({id:'brood-mound-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), gorespiker: Object.freeze({id:'brood-mound-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), spineburrow: Object.freeze({id:'brood-mound-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), silktrap: Object.freeze({id:'brood-tendril-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), tendriltrap: Object.freeze({id:'brood-tendril-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), tendrilmaw: Object.freeze({id:'brood-tendril-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), uplink: Object.freeze({id:'brood-tendril-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), sonicshrieker: Object.freeze({id:'brood-tendril-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), sgen: Object.freeze({id:'brood-tendril-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), thornnest: Object.freeze({id:'brood-nest-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}), raptornest: Object.freeze({id:'brood-nest-v2', source:'semantic-bake', maps:null, surfaces:Object.freeze({})}) }); function infOrganicSurfacePass(geo,pack){ if(!geo)return geo; if(geo.v){ const v=geo.v; for(let o=11;o ({ base: infBldFactory(V.base, k), tur: V.tur ? infBldFactory(V.tur, k) : null })); } } })();