massfront-playtest / src /engine /models-legion.js
CREATORJD's picture
Publish MASSFRONT web 1.33.33 (part 3)
3597f5a verified
Raw
History Blame Contribute Delete
31.8 kB
;
;
/* ============================================================================
RED ASCENDANCY STRUCTURES
----------------------------------------------------------------------------
A separate industrial architecture kit for the Legion/Red Ascendancy. These
are not recoloured Nova buildings: every family uses squat armored plinths,
oversized mechanisms, exposed heat hardware and red command-view livery.
The maps at the bottom deliberately mirror BLD_MDL so old saves keep their
simulation type while receiving the correct faction silhouette at render.
============================================================================ */
const LEG_ARM=C(188,178,172), LEG_ARM_D=C(84,73,75);
const LEG_PANEL=C(146,136,133), LEG_EDGE=C(215,207,200);
const LEG_MACH=C(112,116,124), LEG_TRIM=C(232,218,207);
const LEG_RED=C(245,91,62), LEG_HOT=C(255,151,72);
const LEG_PAD=C(98,92,90), LEG_BORE=C(12,10,11);
COL_MAT.set(LEG_ARM,MAT.TWR_ARMOR); COL_MAT.set(LEG_ARM_D,MAT.TWR_COAT);
COL_MAT.set(LEG_PANEL,MAT.TWR_ARMOR); COL_MAT.set(LEG_EDGE,MAT.TWR_MACH);
COL_MAT.set(LEG_MACH,MAT.TWR_MACH); COL_MAT.set(LEG_TRIM,MAT.TRIM);
COL_MAT.set(LEG_RED,MAT.TWR_ARMOR); COL_MAT.set(LEG_HOT,MAT.TWR_GLOW);
COL_MAT.set(LEG_PAD,MAT.TWR_PAD); COL_MAT.set(LEG_BORE,MAT.TWR_BORE);
COL_TEAM.add(LEG_RED);
function legPad(m,r,h){
r=r||18; h=h||3;
m.cyl(0,0,0,r,r-1.8,h,8,LEG_PAD);
m.cyl(0,h,0,r-3,r-4.4,2.6,8,LEG_ARM_D);
m.ring(0,h+2.62,0,r-5.0,r-3.7,16,LEG_EDGE);
for(let k=0;k<8;k++){
const a=k/8*TAU;
const x=Math.cos(a)*(r-2.2),z=Math.sin(a)*(r-2.2);
m.bevelBox(x,h+0.4,z,3.8,1.5,3.8,.35,k%2?LEG_MACH:LEG_PANEL,a);
if(!(k&1)) m.box(x,h+1.92,z,2.2,.20,.55,k===0?LEG_RED:LEG_HOT,a);
}
return m;
}
function legHeatStack(m,x,y,z,h,r){
r=r||2.1;
m.cyl(x,y,z,r*1.35,r*1.1,h*.30,8,LEG_MACH);
m.cyl(x,y+h*.26,z,r,r*.82,h*.66,8,LEG_ARM_D);
m.ring(x,y+h*.28,z,r*1.02,r*1.24,10,LEG_EDGE);
m.tube(x,y+h*.88,z,r*.9,r*.48,h*.14,8,LEG_BORE);
m.box(x,y+h*.43,z+r*.92,r*.36,h*.32,r*.28,LEG_HOT);
}
function legCore(m,x,y,z,r){
m.cyl(x,y,z,r*1.55,r*1.30,1.6,10,LEG_MACH);
m.sphere(x,y+1.5,z,r,10,LEG_HOT,.92,false);
m.ring(x,y+1.7,z,r*1.32,r*1.62,18,LEG_RED);
}
function legGun(m,len,r,z,tier){
const t=tier||1, L=len+(t-1)*2.2;
m.bevelBox(-2,0,z||0,9+t*1.1,5+t*.4,8+t*.6,.8,LEG_ARM);
m.bevelBox(-2,4.4,z||0,7+t,1.2,5.8,.3,LEG_PANEL);
m.box(-2,5.62,z||0,4.4+t*.4,.22,2.2,LEG_RED);
for(const s of [-1,1]){
m.bevelBox(-2,1.5,(z||0)+s*(4.15+t*.28),5.6+t*.5,2.3,.58,.22,LEG_PANEL);
m.box(-2,3.66,(z||0)+s*(4.47+t*.28),3.2,.18,.62,s>0?LEG_RED:LEG_HOT);
}
tubeX(m,1.4,2.2,z||0,L,r+(t-1)*.12,(r+(t-1)*.12)*.48,12,LEG_BORE);
for(let k=0;k<2+t;k++){
const x=3+k*(L/(2+t));
ringX(m,x,2.2,z||0,r*1.42,r*1.75,12,k===1+t?LEG_HOT:LEG_MACH);
}
m.box(-5.4,1.1,z||0,2.4,3.5,6.4,LEG_MACH);
return m;
}
function mdlLegTurretBase(tier){
const m=MB(),t=tier||1; legPad(m,15+t,3.2);
m.cyl(0,5.6,0,8.2+t*.7,7.2+t*.6,7.2+t,12,LEG_ARM);
m.ring(0,11.0+t,0,6.9+t*.55,7.7+t*.58,16,LEG_PANEL);
m.cyl(0,12.4+t,0,6.2+t*.45,5.2+t*.4,2.2,12,LEG_MACH);
for(const s of [-1,1]){
m.bevelBox(-3,7.0,s*(8.4+t*.5),8+t,4.2,2.5,.45,LEG_PANEL);
m.box(-3,10.85,s*(9.68+t*.5),4+t*.4,.22,.55,s>0?LEG_RED:LEG_HOT);
}
return m.build();
}
function mdlLegTurretGun(tier){ const m=MB(); legGun(m,12,1.25,0,tier); return m.build(); }
function mdlLegBunkerBase(tier){
const m=MB(),t=tier||1; legPad(m,20+t,3.4);
m.bevelBox(0,5.4,0,26+t*2,9+t,22+t*1.5,2.0,LEG_ARM);
m.bevelBox(4,13+t,0,16+t*1.4,2.0,15,.45,LEG_PANEL);
m.box(4,15.05+t,0,9+t,.24,4.5,LEG_RED);
for(const s of [-1,1]){ m.box(-7,6.3,s*11.4,8,5,3,LEG_MACH); legHeatStack(m,-9,10,s*8,8+t,1.6); }
return m.build();
}
function mdlLegBunkerGun(tier){
const m=MB(),t=tier||1;
m.bevelBox(-2,0,0,11+t,5+t*.5,12+t,.9,LEG_ARM);
for(const s of [-1,1]) legGun(m,11+t*1.5,.9,s*(2.1+t*.2),t);
return m.build();
}
function mdlLegBastionBase(tier){
const m=MB(),t=tier||1; legPad(m,22+t*1.2,4);
m.cyl(0,7.5,0,13+t,11+t*.8,13+t,12,LEG_ARM_D);
m.cyl(0,19+t,0,10+t*.8,9+t*.7,3,12,LEG_MACH);
for(let k=0;k<4;k++){
const a=k/4*TAU,x=Math.cos(a)*15,z=Math.sin(a)*15;
m.bevelBox(x,5,z,7,5,8,.6,k%2?LEG_ARM:LEG_PANEL,a);
m.box(x,9.8,z,3.5,.22,4,k===0?LEG_RED:LEG_HOT,a);
}
return m.build();
}
function mdlLegBastionGun(tier){
const m=MB(),t=tier||1;
m.bevelBox(-3,0,0,15+t*1.5,7+t*.8,14+t,1.2,LEG_ARM);
for(const s of [-1,1]){
m.bevelBox(-4,2.1,s*(7.1+t*.5),8+t,3.0,.65,.24,LEG_PANEL);
m.box(-4,4.92,s*(7.45+t*.5),4+t*.3,.2,.7,s>0?LEG_RED:LEG_HOT);
}
tubeX(m,2,3.0,0,17+t*2.5,2.0+t*.2,1.05+t*.12,14,LEG_BORE);
for(let k=0;k<4;k++) ringX(m,5+k*(4+t*.3),3,0,2.5+t*.22,2.9+t*.22,14,k===3?LEG_HOT:LEG_MACH);
for(const s of [-1,1]) m.box(-5,1.2,s*6.4,7,5.5,3.0,LEG_RED);
return m.build();
}
/* The Ascendancy rail battery used to borrow the concussion bastion body and
gun. That saved geometry, but erased the role at phone scale: a recoil-fed
penetrator read as another artillery cannon. The dedicated family below is
deliberately long and low, with separated rails and exposed capacitor
banks. Tier growth adds hardware instead of simply inflating the silhouette. */
function mdlLegRailBase(tier){
const m=MB(),t=tier||1; legPad(m,18+t*1.25,3.6);
m.bevelBox(-1,5.2,0,34+t*2.2,6.5,24+t*1.7,1.3,LEG_ARM_D);
m.bevelBox(-5,11.5,0,22+t*1.6,3.2,17+t,0.6,LEG_ARM);
m.cyl(0,14.7,0,8.0+t*.45,7.2+t*.38,2.2,14,LEG_MACH);
m.ring(0,16.92,0,5.8+t*.32,7.0+t*.38,18,LEG_EDGE);
for(const s of [-1,1]){
const z=s*(10.1+t*.72);
m.bevelBox(-5,7.1,z,13+t,4.4,3.1,.55,LEG_PANEL);
for(let k=0;k<t+1;k++){
const x=-9+k*(7.3/(t||1));
m.cyl(x,10.4,z,1.25,1.05,2.4,8,LEG_MACH);
m.ring(x,12.82,z,.72,1.08,10,k===t?LEG_HOT:LEG_RED);
}
}
m.box(-13,7.0,0,3.2,5.0,9.5,LEG_MACH);
m.box(-13,11.86,0,1.6,.22,4.8,LEG_RED);
return m.build();
}
function mdlLegRailTur(tier){
const m=MB(),t=tier||1,L=15+t*2.0;
m.cyl(0,0,0,7.1+t*.30,6.4+t*.26,2.0,14,LEG_MACH);
m.bevelBox(-3,2.0,0,14+t*1.2,5.8+t*.45,12+t*.65,1.0,LEG_ARM);
m.bevelBox(-4,7.2+t*.35,0,9+t*.65,1.4,8+t*.45,.28,LEG_PANEL);
/* Two real open rail bores create a forked muzzle instead of a flat slab. */
for(const s of [-1,1]){
const z=s*(2.45+t*.18);
cylX(m,2.0,5.0,z,L,1.08+t*.11,.92+t*.09,12,LEG_TRIM,false);
tubeX(m,2.0+L,5.0,z,1.25,1.32+t*.11,.58+t*.06,12,LEG_BORE);
for(let k=0;k<2+t;k++){
const x=3.2+k*(L-2)/(1+t*.75);
ringX(m,x,5.0,z,1.34+t*.10,1.67+t*.10,12,(k+t)&1?LEG_HOT:LEG_MACH);
}
}
for(const s of [-1,1]){
m.bevelBox(-5,3.1,s*(6.25+t*.32),7.0+t*.5,4.8,2.8,.55,LEG_PANEL);
m.box(-5,7.76,s*(7.68+t*.32),3.6,.22,.55,s>0?LEG_RED:LEG_HOT);
}
m.box(-8,2.4,0,3.2,5.4,7.2,LEG_MACH);
return m.build();
}
function mdlLegAA(tier){
const m=MB(),t=tier||1; legPad(m,15+t,3);
m.cyl(0,5,0,8+t*.35,7+t*.25,7+t,12,LEG_ARM);
m.cyl(0,12+t,0,5.4,5.4,2,12,LEG_MACH); legCore(m,0,14+t,0,2.1);
if(t>=3) m.box(0,13+t,0,1.0,.18,6.4,LEG_RED);
return m.build();
}
function mdlLegAAGun(tier){
const m=MB(),t=tier||1; m.bevelBox(-2,0,0,10+t*.4,4.5+t*.25,11+t*.35,.8,LEG_ARM);
for(const s of [-1,1]) m.bevelBox(-2,1.1,s*5.55,6.2,2.2,.55,.18,LEG_PANEL);
for(const s of [-1,1]) for(const q of [-1,1]) tubeX(m,1.5,2+q*1.1,s*2.6,11+t,.62,.30,10,LEG_BORE);
m.box(-4,3.8,0,3,2,7,LEG_RED);
if(t>=3) m.box(-4,5.4,0,2.2,.18,5.2,LEG_HOT);
return m.build();
}
function mdlLegMiningBase(tier){ return mdlLegTurretBase((tier||1)+1); }
function mdlLegMiningGun(tier){
const m=MB(),t=tier||1; m.bevelBox(-2,0,0,12+t,6+t*.5,10+t,.9,LEG_ARM);
for(const s of [-1,1]) m.bevelBox(-3,1.5,s*(5.15+t*.5),7+t,2.8,.58,.2,LEG_PANEL);
tubeX(m,2,2.8,0,14+t*2,1.7+t*.15,.72+t*.08,14,LEG_BORE);
for(let k=0;k<4+t;k++) ringX(m,4+k*2.5,2.8,0,2.0+t*.1,2.35+t*.1,14,k%2?LEG_HOT:LEG_RED);
return m.build();
}
function mdlLegHellfireBase(tier){
const m=MB(),t=tier||1; legPad(m,18+t,3.5);
m.cyl(0,6,0,10+t,8.5+t,10,12,LEG_ARM);
m.cyl(0,16,0,7.2+t*.3,6.6+t*.25,1.8,14,LEG_ARM_D);
m.ring(0,17.82,0,4.8+t*.2,6.2+t*.25,16,LEG_EDGE);
for(const s of [-1,1]){
m.bevelBox(-4,10,s*(10.7+t*.25),5,5,3,.4,LEG_PANEL);
m.box(-4,14.8,s*(12.22+t*.25),2.6,.20,.6,s>0?LEG_RED:LEG_HOT);
}
return m.build();
}
function mdlLegHellfireTur(tier){
const m=MB(),t=tier||1;
m.cyl(0,0,0,6.7+t*.25,6.2+t*.2,2.0,14,LEG_MACH);
m.bevelBox(-1,2,0,13+t,5+t*.5,12+t,1,LEG_ARM);
m.bevelBox(-2,6.3+t*.4,0,8+t*.6,1.2,8+t*.5,.25,LEG_PANEL);
for(const s of [-1,1]) for(const q of [-1,0,1])
tubeX(m,2,4.5+q*1.45,s*2.9,12+t*1.5,.6,.28,9,LEG_BORE);
for(const s of [-1,1]) m.box(-4,6.6,s*(6.05+t*.5),2.8,.20,.55,s>0?LEG_RED:LEG_HOT);
return m.build();
}
function mdlLegArc(tier){
const m=MB(),t=tier||1; legPad(m,17+t,3.4);
m.cyl(0,6,0,10+t,7+t*.7,8+t,10,LEG_ARM_D);
for(let k=0;k<4+t;k++){
const a=k/(4+t)*TAU,rr=8+t*.6;
m.wedge(Math.cos(a)*rr,8,Math.sin(a)*rr,4,12+t*2,3,LEG_ARM,a+Math.PI/2);
}
m.cyl(0,13+t,0,4+t*.4,2.2,9+t*2,10,LEG_MACH); legCore(m,0,23+t*3,0,3+t*.35); return m.build();
}
function mdlLegBarrier(tier){
const m=MB(),t=tier||1; legPad(m,17+t,3.4);
m.cyl(0,6,0,10+t,7+t,9+t,10,LEG_ARM);
for(let k=0;k<6;k++){const a=k/6*TAU;m.wedge(Math.cos(a)*(11+t),5,Math.sin(a)*(11+t),4,16+t*2,4,LEG_ARM_D,a);}
legCore(m,0,16+t,0,4+t*.5); m.ring(0,17+t,0,7+t,8+t,24,LEG_HOT); return m.build();
}
function mdlLegUplink(tier){
const m=MB(),t=tier||1; legPad(m,15+t,3);
m.box(0,5,0,13+t,9+t,12+t,LEG_ARM); m.bevelBox(0,14+t,0,10+t,2,9,.35,LEG_PANEL);
for(const s of [-1,1]) m.box(0,10,s*(6.05+t*.5),6,.25,.45,s>0?LEG_RED:LEG_HOT);
m.cyl(0,16+t,0,1.3,1.0,12+t*3,8,LEG_MACH);
m.ring(0,24+t*3,0,6+t,8+t,24,LEG_TRIM); legCore(m,0,24+t*3,0,1.8+t*.3); return m.build();
}
function mdlLegMissileBase(tier){
const m=MB(),t=tier||1; legPad(m,22+t,4);
m.bevelBox(0,7,0,27+t*2,8,23+t,1.6,LEG_ARM);
for(const s of [-1,1]){
m.bevelBox(-8,10,s*(11.65+t*.5),8,4,.62,.22,LEG_PANEL);
m.box(-8,13.75,s*(12+t*.5),4,.2,.68,s>0?LEG_RED:LEG_HOT);
}
m.cyl(0,15,0,9.2+t*.35,8.5+t*.3,2.0,16,LEG_ARM_D);
m.ring(0,17.02,0,6.3+t*.25,8.0+t*.3,18,LEG_EDGE);
return m.build();
}
function mdlLegMissileTur(tier){
const m=MB(),t=tier||1;
m.cyl(0,0,0,8.6+t*.3,8.0+t*.25,2.0,16,LEG_MACH);
m.bevelBox(-2,2,0,17+t*1.4,8+t*.5,17+t,1.2,LEG_PANEL);
const rows=2+t,cols=2+t;
for(let r=0;r<rows;r++) for(let c=0;c<cols;c++){
const z=(c-(cols-1)/2)*3.5,y=4.5+(r-(rows-1)/2)*2.65;
tubeX(m,5.5,y,z,9+t*1.4,1.18,.62,10,LEG_BORE);
ringX(m,13.8+t*1.4,y,z,1.26,1.62,10,(r+c)&1?LEG_RED:LEG_HOT);
}
m.bevelBox(-8,5.0,0,5.0,5.5,13+t,.65,LEG_ARM);
m.box(-8,10.25,0,2.8,.2,6,LEG_RED);
return m.build();
}
/* NOVA is a map-wide strategic weapon, not an enlarged missile rack. Its
fortress cradle, three heavy launch throats and orbital-control crown make
that importance legible before the player opens a description panel. */
function mdlLegNovaBase(tier){
const m=MB(),t=tier||1; legPad(m,22+t*.65,4);
m.bevelBox(0,6.5,0,43+t*1.5,8.0,34+t,2.0,LEG_ARM_D);
for(const s of [-1,1]){
m.bevelBox(-10,10.0,s*(14.8+t*.45),15+t,6.0,4.0,.75,LEG_ARM);
m.box(-10,15.82,s*(16.82+t*.45),7+t*.5,.22,.58,s>0?LEG_RED:LEG_HOT);
}
m.cyl(2,14.5,0,11.5+t*.35,10.3+t*.3,3.1,16,LEG_PANEL);
m.ring(2,17.62,0,7.6+t*.25,9.8+t*.3,20,LEG_EDGE);
for(let k=0;k<2+t;k++){
const a=k/(2+t)*TAU,x=-13,z=Math.sin(a)*9;
m.cyl(x,7.5,z,1.5,1.25,6.0,9,LEG_MACH);
m.ring(x,13.52,z,.85,1.28,10,k===t?LEG_HOT:LEG_RED);
}
return m.build();
}
function mdlLegNovaTur(tier){
const m=MB(),t=tier||1;
m.cyl(0,0,0,10.2+t*.28,9.4+t*.25,2.3,16,LEG_MACH);
m.bevelBox(-2,2.3,0,18+t,8.0+t*.45,17+t*.55,1.25,LEG_ARM);
const cells=t===1?[-3.2,3.2]:t===2?[-4.1,0,4.1]:[-5.1,-1.7,1.7,5.1];
for(let i=0;i<cells.length;i++){
const z=cells[i];
m.bevelBox(2,5.3,z,12+t*.7,4.7,3.0,.48,LEG_PANEL);
cylX(m,4.0,6.3,z,12+t*1.25,1.48+t*.08,1.30+t*.07,12,LEG_TRIM,false);
tubeX(m,16+t*1.25,6.3,z,1.4,1.78+t*.08,.82+t*.05,12,LEG_BORE);
ringX(m,11.5+t*.8,6.3,z,1.78+t*.08,2.18+t*.09,12,i&1?LEG_RED:LEG_HOT);
}
m.bevelBox(-8,5.2,0,4.6,7.2,13+t,.62,LEG_ARM_D);
m.cyl(-8,12.4,0,1.15,.8,5+t,8,LEG_MACH);
m.ring(-8,17.4+t,0,3.8+t*.25,5.2+t*.3,18,LEG_HOT);
m.box(-8,18.0+t,0,1.0,.25,7+t,LEG_RED);
return m.build();
}
function mdlLegPlasma(tier){
const m=MB(),t=tier||1; legPad(m,19+t,3.8);
m.cyl(0,7,0,12+t,9+t,10+t,10,LEG_ARM_D);
for(let k=0;k<5+t;k++){
const a=k/(5+t)*TAU,x=Math.cos(a)*(10+t),z=Math.sin(a)*(10+t);
m.wedge(x,8,z,4,13+t*2,4,k%2?LEG_ARM:LEG_PANEL,a);
if(!(k&1)) m.box(x,17+t,z,1.1,.22,1.1,LEG_HOT,a);
}
legCore(m,0,17+t,0,5+t*.65); m.ring(0,20+t,0,8+t,9+t,28,LEG_HOT); return m.build();
}
function mdlLegEconomy(kind){
const m=MB(),r=kind==='mex'?19:kind==='geo'?21:18; legPad(m,r,3.5);
if(kind==='mex'){
m.bevelBox(0,5,0,24,9,22,1.5,LEG_ARM); m.cyl(0,14,0,7,5,12,10,LEG_MACH);
for(const s of [-1,1]){
m.bevelBox(s*10,5,0,5,13,8,.5,LEG_PANEL);
m.box(s*10,17.75,0,2.4,.22,4,s>0?LEG_RED:LEG_HOT);
}
}else if(kind==='pgen'||kind==='geo'){
m.cyl(0,6,0,12,9,15,12,LEG_ARM); m.cyl(0,21,0,7,4,6,12,LEG_MACH); legCore(m,0,27,0,3.5);
for(let k=0;k<4;k++){const a=k/4*TAU;legHeatStack(m,Math.cos(a)*12,5,Math.sin(a)*12,12,1.8);}
}else if(kind==='silo'){
for(const s of [-1,1]){m.cyl(s*7,5,0,6,5,25,10,LEG_ARM);m.cyl(s*7,30,0,5,2,5,10,LEG_RED);} legHeatStack(m,0,5,-8,20,2);
}else{
m.bevelBox(-2,5,0,25,14,23,1.5,LEG_ARM); m.bevelBox(-2,19,0,21,3,18,.5,LEG_PANEL);
m.box(-2,22.05,0,12,.24,4.5,LEG_RED);
legHeatStack(m,11,5,8,22,2.5); legHeatStack(m,11,5,-8,18,2.2);
}
return m.build();
}
function mdlLegFactory(kind){
const m=MB(),large=kind==='hq'||kind==='tgate',w=large?72:kind==='airfield'?82:56,d=large?60:kind==='airfield'?38:46;
m.bevelBox(0,0,0,w,5,d,2,LEG_PAD); m.bevelBox(-5,5,0,w-12,large?26:19,d-10,2.4,LEG_ARM);
m.bevelBox(-5,large?31:24,0,w-22,3,d-18,.55,LEG_PANEL);
m.box(-5,large?34.05:27.05,0,w*.32,.24,d*.18,LEG_RED);
for(const s of [-1,1]){m.box(-w*.34,7,s*(d*.40),w*.18,large?22:15,4,LEG_MACH);legHeatStack(m,w*.30,5,s*(d*.32),large?26:19,2.2);}
if(kind==='airfield'||kind==='harbor') m.box(w*.24,5,0,w*.38,3,d*.64,LEG_MACH);
if(kind==='techlab'){ legCore(m,4,26,0,5); m.ring(4,28,0,9,11,28,LEG_HOT); }
if(kind==='tgate'){ m.ring(5,33,0,16,20,30,LEG_HOT); m.ring(5,33,0,21,23,30,LEG_MACH); }
if(kind==='hq'){
m.bevelBox(4,34,0,31,14,30,2,LEG_ARM); m.bevelBox(4,48,0,24,4,22,.6,LEG_PANEL);
m.box(4,52.05,0,13,.25,5.5,LEG_RED);
}
return m.build();
}
function mdlLegWall(){
const m=MB();m.bevelBox(0,0,0,34,8,16,1.5,LEG_PAD);m.bevelBox(0,8,0,30,11,12,1.4,LEG_ARM);
m.bevelBox(0,10.5,-6.1,15,5,.5,.16,LEG_ARM_D);
m.bevelBox(0,19,0,24,3,8,.45,LEG_PANEL);m.box(0,22.05,0,12,.22,2.2,LEG_RED);
for(const s of [-1,1]){
m.box(s*11,11,s*6.05,4,5,.3,LEG_EDGE);
m.box(s*11,15.4,s*6.24,1.6,.22,.36,LEG_HOT);
}
return m.build();
}
function mdlLegGate(){
const m=MB();m.bevelBox(0,0,0,42,5,18,1.4,LEG_PAD);
for(const s of [-1,1]){
m.bevelBox(s*16,5,0,9,22,14,1.4,LEG_ARM);m.bevelBox(s*16,27,0,7,3,10,.4,LEG_PANEL);
m.box(s*16,30.05,0,3.4,.22,3,s>0?LEG_RED:LEG_HOT);
}
m.bevelBox(0,5,0,22,13,5,.35,LEG_ARM_D);m.box(0,17.8,0,11,.22,5.2,LEG_EDGE);return m.build();
}
function mdlLegSeafortBase(tier){
const m=MB(),t=tier||1;
m.bevelBox(0,0,0,42,4.2,36,1.6,LEG_PAD);
m.bevelBox(0,4.2,0,38,2.0,32,.55,LEG_PANEL);
for(const s of [-1,1]){
m.bevelBox(-4,0,s*16.8,30,3.4,5.2,.7,LEG_ARM);
m.box(-4,3.42,s*16.95,16,.22,1.6,s>0?LEG_RED:LEG_HOT);
legHeatStack(m,-14,4.2,s*12.5,9+t,1.7);
}
m.cyl(0,6.2,0,11+t*.3,9.5+t*.25,8.5,12,LEG_ARM_D);
m.cyl(0,14.5,0,8.4+t*.25,7.6+t*.2,2.0,14,LEG_MACH);
m.ring(0,16.52,0,5.8+t*.2,7.4+t*.22,16,LEG_EDGE);
return m.build();
}
function mdlLegSeafortGun(tier){
const m=MB(),t=tier||1;
m.bevelBox(-2,0,0,13+t,5.6+t*.4,13+t,.9,LEG_ARM);
tubeX(m,2,2.6,0,14+t*1.6,1.85+t*.12,.92+t*.08,12,LEG_BORE);
for(let k=0;k<3;k++) ringX(m,5+k*3.2,2.6,0,2.2+t*.1,2.55+t*.1,12,k===2?LEG_HOT:LEG_MACH);
for(const s of [-1,1]){
m.bevelBox(-3,1.4,s*(6.4+t*.3),7,2.4,.55,.2,LEG_PANEL);
tubeX(m,1.2,4.8,s*3.0,11+t,0.62,0.30,9,LEG_BORE);
m.box(-3,3.72,s*(6.7+t*.3),3.6,.2,.62,s>0?LEG_RED:LEG_HOT);
}
m.box(-5.4,4.6,0,2.8,.22,6.4,LEG_RED);
return m.build();
}
function mdlLegStormBase(tier){
const m=MB(),t=tier||1; legPad(m,20+t*.4,3.8);
m.bevelBox(0,6.4,0,34+t,7.2,28+t,1.4,LEG_ARM_D);
for(const s of [-1,1]){
m.bevelBox(-2,10,s*(12.6+t*.3),16,5.2,4.0,.55,LEG_PANEL);
for(const x of [-6,2,10]){
m.cyl(x,14.8,s*(12.6+t*.3),1.35,1.1,4.2+t*.6,8,LEG_MACH);
m.tube(x,18.9+t*.6,s*(12.6+t*.3),1.15,.55,.45,8,LEG_BORE);
m.ring(x,19.5+t*.6,s*(12.6+t*.3),.7,1.1,10,x===2?LEG_HOT:LEG_RED);
}
}
m.cyl(0,13.4,0,8.8+t*.25,8.0+t*.2,2.2,14,LEG_MACH);
m.ring(0,15.62,0,6.2+t*.2,8.0+t*.22,16,LEG_EDGE);
return m.build();
}
function mdlLegStormTur(tier){
const m=MB(),t=tier||1;
m.cyl(0,0,0,8.2+t*.2,7.6+t*.18,2.0,14,LEG_MACH);
m.bevelBox(-2,2,0,16+t,7.2+t*.4,16+t,.95,LEG_ARM);
for(let r=0;r<4;r++) for(let c=0;c<4;c++){
const y=4.2+(r-1.5)*2.05,z=(c-1.5)*3.15;
m.bevelBox(3.6,y-1.05,z,3.4,2.15,2.4,.28,LEG_PANEL);
tubeX(m,5.2,y,z,2.2,1.12,.62,8,LEG_BORE);
}
m.box(-7.2,5.4,0,3.2,5.6,10.5,LEG_ARM_D);
m.box(-7.2,10.9,0,1.4,.22,6.4,LEG_RED);
return m.build();
}
function mdlLegNest(){
/* Nest is Brood-owned at runtime (bldFactionKey forces horde). This Legion
fallback used to alias HQ — a 72-wide keep for a hatchery slot. A sealed
quarantine redoubt keeps the catalogue readable as Dominion iron without
growing tissue or cloning the command keep. */
const m=MB();
legPad(m,20,3.4);
m.bevelBox(0,5.4,0,26,9,22,1.8,LEG_ARM);
m.bevelBox(0,14.4,0,20,1.8,16,.45,LEG_PANEL);
m.box(0,16.25,0,10,.22,4.2,LEG_RED);
m.cyl(0,16.2,0,6.4,5.2,5.5,12,LEG_MACH);
m.cyl(0,21.7,0,4.6,3.0,2.0,12,LEG_PANEL);
m.tube(0,23.7,0,3.0,1.4,1.2,10,LEG_BORE);
m.ring(0,24.9,0,1.8,3.2,14,LEG_HOT);
for(const s of [-1,1]){
m.bevelBox(s*11.2,6.2,0,5.6,7.0,8.0,.6,LEG_PANEL);
m.box(s*11.2,13.15,0,3.2,.22,2.0,s>0?LEG_RED:LEG_HOT);
legHeatStack(m,s*11.2,13.4,s*6.0,8,1.5);
}
return m.build();
}
const BLD_MDL_LEGION={
mex:()=>mdlLegEconomy('mex'),pgen:()=>mdlLegEconomy('pgen'),geo:()=>mdlLegEconomy('geo'),silo:()=>mdlLegEconomy('silo'),fab:()=>mdlLegEconomy('fab'),
fac:()=>mdlLegFactory('fac'),tgate:()=>mdlLegFactory('tgate'),harbor:()=>mdlLegFactory('harbor'),airfield:()=>mdlLegFactory('airfield'),
techlab:()=>mdlLegFactory('techlab'),hq:()=>mdlLegFactory('hq'),nest:()=>mdlLegNest(),
turret:mdlLegTurretBase,bunker:mdlLegBunkerBase,bastion:mdlLegBastionBase,aatower:mdlLegAA,
minelaser:mdlLegMiningBase,missilebastion:mdlLegMissileBase,hellstorm:mdlLegHellfireBase,arc:mdlLegArc,
sgen:mdlLegBarrier,uplink:mdlLegUplink,nova:mdlLegNovaBase,plasma:mdlLegPlasma,
rail:mdlLegRailBase,wall:mdlLegWall,gate:mdlLegGate,
seafort:mdlLegSeafortBase,stormcaller:mdlLegStormBase,
};
const BLD_TUR_MDL_LEGION={
turret:mdlLegTurretGun,bunker:mdlLegBunkerGun,bastion:mdlLegBastionGun,
aatower:mdlLegAAGun,minelaser:mdlLegMiningGun,rail:mdlLegRailTur,
hellstorm:mdlLegHellfireTur,nova:mdlLegNovaTur,missilebastion:mdlLegMissileTur,
seafort:mdlLegSeafortGun,stormcaller:mdlLegStormTur,
};
const BLD_TUR_H_LEGION={
turret:14,bunker:17,bastion:22,aatower:12,minelaser:15,rail:17,
hellstorm:17.8,nova:17.7,missilebastion:17,seafort:16.5,stormcaller:15.6,
};
const BLD_TUR_S_LEGION={
turret:1.13,bunker:1.10,bastion:1.11,aatower:1.12,minelaser:1.10,rail:1.0,
hellstorm:1.0,nova:1.0,missilebastion:1.0,seafort:1.08,stormcaller:1.05,
};
/* Stage D1 — isolated Legion landmark packs. These are per-building semantic
bakes, not a faction-wide colour wash: the shared battle material still owns
lighting/AO/microdetail, while each landmark chooses its own armor, machine
and heat vocabulary. `maps:null` deliberately records that no bespoke
authored UV BaseAO/NRE/mask export exists yet. Keeping the selector here,
next to the actual builders, makes a later authored-map replacement local
and avoids changing the generic building renderer. */
const DOM_LEGION_STRUCTURE_PACKS=Object.freeze({
hq:Object.freeze({
id:'legion-hq-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_CAST,[MAT.TWR_COAT]:MAT.LEGION_RIVET,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
fac:Object.freeze({
id:'legion-fac-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_RIVET,[MAT.TWR_COAT]:MAT.LEGION_CAST,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
techlab:Object.freeze({
id:'legion-techlab-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_RIVET,[MAT.TWR_COAT]:MAT.LEGION_CAST,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
pgen:Object.freeze({
id:'legion-pgen-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_CAST,[MAT.TWR_COAT]:MAT.LEGION_SIEGE,
[MAT.TWR_MACH]:MAT.LEGION_RIVET,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
mex:Object.freeze({
id:'legion-mex-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_RIVET,[MAT.TWR_COAT]:MAT.LEGION_CAST,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
geo:Object.freeze({
id:'legion-geo-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_CAST,[MAT.TWR_COAT]:MAT.LEGION_RIVET,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
airfield:Object.freeze({
id:'legion-airfield-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_RIVET,[MAT.TWR_COAT]:MAT.LEGION_CAST,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
rail:Object.freeze({
id:'legion-rail-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_CAST,[MAT.TWR_COAT]:MAT.LEGION_RIVET,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
uplink:Object.freeze({
id:'legion-uplink-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_RIVET,[MAT.TWR_COAT]:MAT.LEGION_CAST,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
turret:Object.freeze({
id:'legion-turret-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_CAST,[MAT.TWR_COAT]:MAT.LEGION_RIVET,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
bunker:Object.freeze({
id:'legion-bunker-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_CAST,[MAT.TWR_COAT]:MAT.LEGION_RIVET,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
bastion:Object.freeze({
id:'legion-bastion-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_CAST,[MAT.TWR_COAT]:MAT.LEGION_RIVET,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
aatower:Object.freeze({
id:'legion-aatower-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_RIVET,[MAT.TWR_COAT]:MAT.LEGION_CAST,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
minelaser:Object.freeze({
id:'legion-minelaser-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_RIVET,[MAT.TWR_COAT]:MAT.LEGION_CAST,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
missilebastion:Object.freeze({
id:'legion-missilebastion-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_CAST,[MAT.TWR_COAT]:MAT.LEGION_RIVET,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
hellstorm:Object.freeze({
id:'legion-hellstorm-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_CAST,[MAT.TWR_COAT]:MAT.LEGION_RIVET,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
seafort:Object.freeze({
id:'legion-seafort-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_CAST,[MAT.TWR_COAT]:MAT.LEGION_RIVET,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
stormcaller:Object.freeze({
id:'legion-stormcaller-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_CAST,[MAT.TWR_COAT]:MAT.LEGION_RIVET,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
arc:Object.freeze({
id:'legion-arc-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_RIVET,[MAT.TWR_COAT]:MAT.LEGION_CAST,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
sgen:Object.freeze({
id:'legion-sgen-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_RIVET,[MAT.TWR_COAT]:MAT.LEGION_CAST,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
plasma:Object.freeze({
id:'legion-plasma-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_CAST,[MAT.TWR_COAT]:MAT.LEGION_RIVET,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
wall:Object.freeze({
id:'legion-wall-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_RIVET,[MAT.TWR_COAT]:MAT.LEGION_CAST,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
gate:Object.freeze({
id:'legion-gate-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_RIVET,[MAT.TWR_COAT]:MAT.LEGION_CAST,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
nest:Object.freeze({
id:'legion-nest-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_CAST,[MAT.TWR_COAT]:MAT.LEGION_RIVET,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
harbor:Object.freeze({
id:'legion-harbor-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_RIVET,[MAT.TWR_COAT]:MAT.LEGION_CAST,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
tgate:Object.freeze({
id:'legion-tgate-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_RIVET,[MAT.TWR_COAT]:MAT.LEGION_CAST,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
silo:Object.freeze({
id:'legion-silo-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_CAST,[MAT.TWR_COAT]:MAT.LEGION_RIVET,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
fab:Object.freeze({
id:'legion-fab-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_RIVET,[MAT.TWR_COAT]:MAT.LEGION_CAST,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
}),
nova:Object.freeze({
id:'legion-nova-v2',source:'semantic-bake', maps:null,
surfaces:Object.freeze({
[MAT.TWR_ARMOR]:MAT.LEGION_CAST,[MAT.TWR_COAT]:MAT.LEGION_RIVET,
[MAT.TWR_MACH]:MAT.LEGION_SIEGE,[MAT.TWR_GLOW]:MAT.LEGION_THERMITE,
[MAT.TWR_PAD]:MAT.LEGION_SIEGE,[MAT.TRIM]:MAT.LEGION_RIVET
})
})
});
function domLegionStructureSurfacePass(geo,pack){
if(!geo||!geo.v||!pack)return geo;
const v=geo.v;
for(let o=11;o<v.length;o+=VFLOATS){
const raw=v[o],sgn=raw<0?-1:1,packed=Math.abs(raw);
const whole=Math.floor(packed),src=whole-1;
const dst=pack.surfaces[src];
if(dst!==undefined)v[o]=sgn*((dst+1)+(packed-whole));
}
return geo;
}
function domLegionStructureFactory(fn,key){
return function(...args){return domLegionStructureSurfacePass(fn(...args),DOM_LEGION_STRUCTURE_PACKS[key]);};
}
for(const k of ['hq','fac','techlab','pgen','mex','geo','airfield','rail','uplink','turret','bunker','bastion','aatower','minelaser','missilebastion','hellstorm','arc','sgen','plasma','wall','gate','seafort','stormcaller','nest','harbor','tgate','silo','fab','nova'])
if(BLD_MDL_LEGION[k]) BLD_MDL_LEGION[k]=domLegionStructureFactory(BLD_MDL_LEGION[k],k);
for(const k of ['turret','bunker','bastion','aatower','minelaser','rail','hellstorm','nova','missilebastion','seafort','stormcaller'])
if(BLD_TUR_MDL_LEGION[k]) BLD_TUR_MDL_LEGION[k]=domLegionStructureFactory(BLD_TUR_MDL_LEGION[k],k==='nova'?'hellstorm':k);
const BLD_TIER_MDL_LEGION={};
for(const k of ['turret','bunker','bastion','aatower','minelaser','rail']) BLD_TIER_MDL_LEGION[k]=[1,2,3].map(t=>({base:()=>BLD_MDL_LEGION[k](t),tur:()=>BLD_TUR_MDL_LEGION[k](t)}));
for(const k of ['hellstorm','nova','missilebastion','seafort','stormcaller'])
BLD_TIER_MDL_LEGION[k]=[1,2,3].map(t=>({base:()=>BLD_MDL_LEGION[k](t),tur:()=>BLD_TUR_MDL_LEGION[k](t)}));
for(const k of ['arc','sgen','uplink','plasma']) BLD_TIER_MDL_LEGION[k]=[1,2,3].map(t=>({base:()=>BLD_MDL_LEGION[k](t)}));