// Material ids, the material table (def), per-material property arrays, cell flags and part // ids, and drill/tank tiers. // ---------- Material ids ---------- const EMPTY = 0, GRASS = 1, DIRT = 2, LDIRT = 3, SAND = 4, GRAVEL = 5, CLAY = 6, STONE = 7, GRANITE = 8, BASALT = 9, WOOD = 10, LEAVES = 11, COALV = 12, COAL = 13, CUV = 14, CUORE = 15, FEV = 16, FEORE = 17, ASH = 18, SLAG = 19, BRICK = 20, GLASS = 21, COPPER = 22, IRON = 23, STEEL = 24, WATER = 25, MAGMA = 26, MCU = 27, MFE = 28, MST = 29, MGL = 30, STEAM = 31, SMOKE = 32, FIRE = 33, BELTL = 34, BELTR = 35, SHAFT = 36, GATE = 37, HULL = 38, SPRING = 39, RSTONE = 40, RGRAN = 41, RBAS = 42, LCLAY = 43, LWOOD = 44, RBRICK = 45, CULLET = 46, SCRCU = 47, SCRFE = 48, SCRST = 49, BARCU = 50, BARFE = 51, BARST = 52, ACORN = 53, CHARCOAL = 54, SNOW = 55, ICE = 56, SNV = 57, SNORE = 58, TIN = 59, MSN = 60, SCRSN = 61, BARSN = 62, ZNV = 63, ZNORE = 64, ZINC = 65, MZN = 66, SCRZN = 67, BARZN = 68, AGV = 69, AGORE = 70, SILVER = 71, MAG = 72, SCRAG = 73, BARAG = 74, AUV = 75, AUORE = 76, GOLD = 77, MAU = 78, SCRAU = 79, BARAU = 80, BRONZE = 81, MBZ = 82, SCRBZ = 83, BARBZ = 84, BRASS = 85, MBS = 86, SCRBS = 87, BARBS = 88, DOCKW = 89, MSLAG = 90, PIPE = 91, BARGL = 92, CUTST = 93, BARSB = 94; const NMAT = 95; const MD = []; function def(id, o) { MD[id] = Object.assign({ id, name: '?', ph: PH_SOLID, col: [255, 0, 255], v: 10, dens: 2, k: 0.01, cap: 1, hard: 1, yld: id, melt: 0, meltTo: 0, smelt: 0, freeze: 0, freezeTo: 0, boil: 0, boilTo: 0, condT: 0, condTo: 0, ign: 0, flame: 0, flameF: 0, fuel: 0, burnTo: 0, ashP: 0, fluid: 1, spread: 4, stick: 1, alpha: 1, liqT: 0, bag: false, partMat: false, desc: '' }, o); } def(EMPTY, { name: 'Air', ph: PH_EMPTY, k: 0.006, cap: 0.3, hard: 0, yld: 0 }); def(GRASS, { name: 'Grass', col: [78, 142, 62], v: 16, k: 0.008, hard: 1, yld: LDIRT }); def(DIRT, { name: 'Packed dirt', col: [108, 76, 50], v: 14, k: 0.008, hard: 1, yld: LDIRT }); def(LDIRT, { name: 'Dirt', ph: PH_POWDER, col: [124, 88, 58], v: 14, dens: 1.3, k: 0.007, hard: 0, stick: 0.55, bag: true, desc: 'Loose soil. Falls and piles up.' }); def(SAND, { name: 'Sand', ph: PH_POWDER, col: [216, 192, 132], v: 12, dens: 1.6, k: 0.007, hard: 0, melt: 1300, meltTo: MGL, bag: true, desc: 'Melts into glass near 1300°C.' }); def(GRAVEL, { name: 'Gravel', ph: PH_POWDER, col: [124, 121, 116], v: 30, dens: 1.9, k: 0.01, hard: 0, melt: 1250, meltTo: MAGMA, bag: true, desc: 'Loose rock. Falls like sand.' }); def(CLAY, { name: 'Clay', col: [172, 108, 88], v: 8, dens: 1.8, k: 0.009, hard: 1, yld: LCLAY, desc: 'Holds its shape. Fires into brick above ~900°C.' }); def(STONE, { name: 'Stone', col: [106, 106, 112], v: 12, k: 0.012, hard: 3, melt: 1250, meltTo: MAGMA, yld: RSTONE, desc: 'Common rock. Slumps into magma at 1250°C.' }); def(GRANITE, { name: 'Granite', col: [152, 118, 116], v: 24, k: 0.012, hard: 5, melt: 1260, meltTo: MAGMA, yld: RGRAN, desc: 'Hard rock. Needs an iron bit.' }); def(BASALT, { name: 'Basalt', col: [50, 50, 58], v: 10, k: 0.012, hard: 6, melt: 1350, meltTo: MAGMA, yld: RBAS, desc: 'The hardest rock. Needs a steel bit.' }); def(WOOD, { name: 'Wood', col: [184, 136, 82], v: 10, k: 0.005, cap: 1.2, hard: 2, ign: 300, flame: 850, flameF: 1150, fuel: 200, burnTo: ASH, ashP: 0.5, yld: LWOOD, desc: 'Burns around 850°C. Builds water wheels and shafts.' }); def(LEAVES, { name: 'Leaves', col: [54, 118, 52], v: 24, k: 0.004, hard: 0, yld: 0, ign: 240, flame: 650, flameF: 800, fuel: 20, burnTo: EMPTY }); def(COALV, { name: 'Coal seam', col: [40, 38, 41], v: 12, k: 0.01, hard: 2, yld: COAL, ign: 430, flame: 1350, flameF: 2000, fuel: 250, burnTo: ASH, ashP: 0.15 }); def(COAL, { name: 'Coal', ph: PH_POWDER, col: [32, 31, 35], v: 12, dens: 1.1, k: 0.02, hard: 0, ign: 420, flame: 1350, flameF: 2000, fuel: 250, burnTo: ASH, ashP: 0.15, bag: true, desc: 'Fuel. ~1350°C in still air, ~2000°C with forced air.' }); def(CUV, { name: 'Copper ore vein', col: [66, 142, 116], v: 34, k: 0.012, hard: 3, yld: CUORE, melt: 1085, meltTo: MCU, smelt: 0.65 }); def(CUORE, { name: 'Copper ore', ph: PH_POWDER, col: [76, 152, 126], v: 30, dens: 3.0, k: 0.012, hard: 0, melt: 1085, meltTo: MCU, smelt: 0.65, bag: true, desc: 'Melts at 1085°C into copper and slag. Mix it about half and half with coal: ore blocks air, so a layer of ore smothers the fire under it.' }); def(FEV, { name: 'Iron ore vein', col: [142, 78, 60], v: 26, k: 0.012, hard: 4, yld: FEORE, melt: 1538, meltTo: MFE, smelt: 0.6 }); def(FEORE, { name: 'Iron ore', ph: PH_POWDER, col: [154, 88, 66], v: 26, dens: 3.5, k: 0.012, hard: 0, melt: 1538, meltTo: MFE, smelt: 0.6, bag: true, desc: 'Melts at 1538°C into iron and slag.' }); def(ASH, { name: 'Ash', ph: PH_POWDER, col: [152, 149, 144], v: 18, dens: 0.5, k: 0.003, hard: 0, stick: 0.5, melt: 1250, meltTo: MSLAG, bag: true, desc: 'What is left after a fire. Fuses into slag in a fire hotter than 1250°C.' }); def(SLAG, { name: 'Slag', ph: PH_POWDER, col: [76, 66, 64], v: 34, dens: 2.4, k: 0.006, hard: 0, melt: 1150, meltTo: MSLAG, bag: true, desc: 'Smelting waste. Melts again above 1150°C. Knocking out a mold rakes it off the grate above.' }); def(MSLAG, { name: 'Molten slag', ph: PH_LIQUID, col: [232, 112, 40], v: 16, dens: 3.6, k: 0.02, cap: 1.2, hard: 0, freeze: 1000, freezeTo: SLAG, fluid: 0.5, spread: 10, liqT: 1150, desc: 'Smelting waste. Trickles down through the charge but is too thick to pass a grate, so it pools there and sets into slag. Knocking out the mold below rakes it away.' }); def(BRICK, { name: 'Brick', col: [168, 76, 56], v: 16, k: 0.004, hard: 3, melt: 1750, meltTo: MAGMA, yld: RBRICK, desc: 'Fired clay. Insulates and survives 1750°C.' }); def(GLASS, { name: 'Glass', col: [178, 216, 224], v: 6, k: 0.006, hard: 2, melt: 1300, meltTo: MGL, alpha: 0.45, yld: CULLET, desc: 'Clear. Lets light through.' }); def(COPPER, { name: 'Copper', col: [200, 122, 76], v: 8, k: 0.04, cap: 1.5, hard: 4, melt: 1085, meltTo: MCU, yld: SCRCU, desc: 'Conducts heat well. Belts, tubes, fans, engines.' }); def(IRON, { name: 'Iron', col: [128, 131, 138], v: 8, k: 0.035, cap: 1.5, hard: 5, melt: 1538, meltTo: MFE, yld: SCRFE, desc: 'Strong metal. Melts at 1538°C.' }); def(STEEL, { name: 'Steel', col: [172, 180, 192], v: 6, k: 0.035, cap: 1.5, hard: 6, melt: 1450, meltTo: MST, yld: SCRST, desc: 'Iron refined by blowing air through it while molten. The best bit material.' }); def(WATER, { name: 'Water', ph: PH_LIQUID, col: [44, 100, 194], v: 6, dens: 1, k: 0.02, cap: 4, hard: 0, boil: 100, boilTo: STEAM, fluid: 1, spread: 48, alpha: 0.78, liqT: 20, bag: true, desc: 'Boils at 100°C. Steam that rises into the open sky comes back down as rain.' }); def(MAGMA, { name: 'Magma', ph: PH_LIQUID, col: [255, 96, 26], v: 20, dens: 2.7, k: 0.012, cap: 1.2, hard: 0, freeze: 1100, freezeTo: BASALT, fluid: 0.25, spread: 10, liqT: 1250, bag: true, desc: 'Molten rock. Freezes into basalt below 1100°C.' }); def(MCU, { name: 'Molten copper', ph: PH_LIQUID, col: [255, 152, 62], v: 10, dens: 8, k: 0.04, cap: 1.5, hard: 0, freeze: 1080, freezeTo: COPPER, fluid: 0.7, spread: 20, liqT: 1160, bag: true, desc: 'Sets into copper below 1080°C.' }); def(MFE, { name: 'Molten iron', ph: PH_LIQUID, col: [255, 192, 92], v: 10, dens: 7, k: 0.035, cap: 1.5, hard: 0, freeze: 1530, freezeTo: IRON, fluid: 0.6, spread: 20, liqT: 1610, bag: true, desc: 'Sets into iron below 1530°C.' }); def(MST, { name: 'Molten steel', ph: PH_LIQUID, col: [255, 222, 142], v: 10, dens: 7.2, k: 0.035, cap: 1.5, hard: 0, freeze: 1440, freezeTo: STEEL, fluid: 0.6, spread: 20, liqT: 1520, bag: true, desc: 'Sets into steel below 1440°C.' }); def(MGL, { name: 'Molten glass', ph: PH_LIQUID, col: [255, 172, 82], v: 8, dens: 2.3, k: 0.006, cap: 1, hard: 0, freeze: 1200, freezeTo: GLASS, fluid: 0.12, spread: 5, liqT: 1350, bag: true, desc: 'Thick and slow. Sets into glass below 1200°C.' }); def(STEAM, { name: 'Steam', ph: PH_GAS, col: [214, 222, 232], v: 10, dens: 0.3, k: 0.006, cap: 0.4, hard: 0, condT: 97, condTo: WATER, alpha: 0.42, desc: 'Rises. Under a roof it turns back into water below 97°C; in the open sky it rises into the clouds and comes back down as rain.' }); def(SMOKE, { name: 'Smoke', ph: PH_GAS, col: [62, 60, 62], v: 14, dens: 0.4, k: 0.004, cap: 0.3, hard: 0, alpha: 0.55, desc: 'Burning fuel gives it off. It rises, and a fire that cannot vent it chokes.' }); def(FIRE, { name: 'Flame', ph: PH_GAS, col: [255, 150, 40], v: 40, dens: 0.2, k: 0.02, cap: 0.3, hard: 0, alpha: 0.9 }); def(BELTL, { name: 'Belt', col: [66, 68, 74], v: 4, k: 0.03, hard: 2, melt: 1085, meltTo: MCU, partMat: true }); def(BELTR, { name: 'Belt', col: [66, 68, 74], v: 4, k: 0.03, hard: 2, melt: 1085, meltTo: MCU, partMat: true }); def(SHAFT, { name: 'Shaft', col: [150, 110, 64], v: 6, k: 0.005, hard: 2, ign: 340, flame: 800, flameF: 1000, fuel: 140, burnTo: ASH, ashP: 0.3, partMat: true }); def(GATE, { name: 'Gate', col: [146, 74, 58], v: 6, k: 0.004, hard: 3, melt: 1750, meltTo: MAGMA, partMat: true }); def(SPRING, { name: 'Spring', col: [92, 112, 128], v: 30, k: 0.012, hard: 9, yld: 0, desc: 'Groundwater seeps out of this rock whenever there is room next to it.' }); def(RSTONE, { name: 'Stone rubble', ph: PH_POWDER, col: [126, 125, 130], v: 30, dens: 1.8, k: 0.01, hard: 0, melt: 1250, meltTo: MAGMA, bag: true, desc: 'Broken stone. 16 grains make a stone block.' }); def(RGRAN, { name: 'Granite rubble', ph: PH_POWDER, col: [164, 128, 124], v: 32, dens: 1.9, k: 0.01, hard: 0, melt: 1260, meltTo: MAGMA, bag: true, desc: 'Broken granite. Makes granite blocks.' }); def(RBAS, { name: 'Basalt rubble', ph: PH_POWDER, col: [72, 72, 80], v: 20, dens: 2.0, k: 0.01, hard: 0, melt: 1350, meltTo: MAGMA, bag: true, desc: 'Broken basalt. Basalt blocks survive 1350°C.' }); def(LCLAY, { name: 'Clay lumps', ph: PH_POWDER, col: [182, 116, 94], v: 16, dens: 1.6, k: 0.008, hard: 0, stick: 0.25, bag: true, desc: 'Sticky lumps. Clay blocks, grates and gates. Fires into brick above ~900°C.' }); def(LWOOD, { name: 'Wood chunks', ph: PH_POWDER, col: [208, 160, 98], v: 20, dens: 0.6, k: 0.005, cap: 1.2, hard: 0, stick: 0.45, ign: 280, flame: 850, flameF: 1150, fuel: 160, burnTo: ASH, ashP: 0.4, bag: true, desc: 'Fuel that floats on water. Wooden blocks, shafts and water wheels.' }); def(RBRICK, { name: 'Brick rubble', ph: PH_POWDER, col: [174, 88, 66], v: 26, dens: 1.7, k: 0.004, hard: 0, melt: 1750, meltTo: MAGMA, bag: true, desc: 'Broken or fired brick. 16 grains make a brick block.' }); def(CULLET, { name: 'Glass shards', ph: PH_POWDER, col: [196, 228, 236], v: 22, dens: 1.5, k: 0.006, hard: 0, melt: 1300, meltTo: MGL, alpha: 0.75, bag: true, desc: 'Broken glass. Glass blocks, or melt it back down.' }); def(SCRCU, { name: 'Copper scrap', ph: PH_POWDER, col: [192, 118, 74], v: 36, dens: 5, k: 0.035, cap: 1.5, hard: 0, stick: 0.7, melt: 1085, meltTo: MCU, bag: true, desc: 'Copper that set outside a mold. Melt it again and cast it.' }); def(SCRFE, { name: 'Iron scrap', ph: PH_POWDER, col: [124, 126, 132], v: 30, dens: 5, k: 0.03, cap: 1.5, hard: 0, stick: 0.7, melt: 1538, meltTo: MFE, bag: true, desc: 'Iron that set outside a mold. Melt it again and cast it.' }); def(SCRST, { name: 'Steel scrap', ph: PH_POWDER, col: [168, 176, 188], v: 28, dens: 5, k: 0.03, cap: 1.5, hard: 0, stick: 0.7, melt: 1450, meltTo: MST, bag: true, desc: 'Steel that set outside a mold. Melt it again and cast it.' }); def(BARCU, { name: 'Copper bar', ph: PH_ITEM, col: [214, 132, 82], v: 0, dens: 8.9, k: 0, hard: 0, melt: 1085, meltTo: MCU, bag: true, desc: 'A cast bar. Belts, screw tubes, fans and engines are made from these.' }); def(BARFE, { name: 'Iron bar', ph: PH_ITEM, col: [140, 143, 150], v: 0, dens: 7.9, k: 0, hard: 0, melt: 1538, meltTo: MFE, bag: true, desc: 'A cast bar of iron.' }); def(BARST, { name: 'Steel bar', ph: PH_ITEM, col: [184, 192, 204], v: 0, dens: 7.9, k: 0, hard: 0, melt: 1450, meltTo: MST, bag: true, desc: 'A cast bar of steel.' }); def(ACORN, { name: 'Acorn', ph: PH_POWDER, col: [150, 104, 56], v: 22, dens: 0.9, k: 0.006, hard: 0, stick: 0.6, ign: 300, flame: 700, flameF: 900, fuel: 30, burnTo: ASH, ashP: 0.3, bag: true, desc: 'A tree seed. Left on dirt or grass under open sky, it sprouts and grows into a tree.' }); def(CHARCOAL, { name: 'Charcoal', ph: PH_POWDER, col: [58, 50, 46], v: 16, dens: 0.45, k: 0.012, hard: 0, stick: 0.8, ign: 340, flame: 1300, flameF: 1950, fuel: 200, burnTo: ASH, ashP: 0.06, bag: true, desc: 'Wood baked without air. Burns nearly as hot as coal, leaves little ash, and floats.' }); def(SNOW, { name: 'Snow', ph: PH_POWDER, col: [232, 238, 246], v: 10, dens: 0.35, k: 0.004, cap: 0.5, hard: 0, stick: 0.4, melt: 0.5, meltTo: WATER, bag: true, desc: 'Melts into water above 0°C. Floats on water.' }); def(ICE, { name: 'Ice', col: [178, 214, 238], v: 12, k: 0.03, cap: 0.5, hard: 1, melt: 0.5, meltTo: WATER, alpha: 0.85, yld: SNOW, desc: 'Frozen water. Melts above 0°C; drills into snow.' }); // A metal family: vein in the rock, loose ore, cast solid, molten, scrap and bar. function metalFamily(o) { const { vein, ore, solid, molten, scrap, bar, name, col, mcol, melt, dens, k, hardOre, hardVein, smelt, oreCol, desc } = o; if (vein) def(vein, { name: name + ' ore vein', col: oreCol.map(c => c - 10), v: 34, k: 0.012, hard: hardVein, yld: ore, melt: smelt, meltTo: molten, smelt: 0.6 }); if (ore) def(ore, { name: name + ' ore', ph: PH_POWDER, col: oreCol, v: 30, dens: 3.2, k: 0.012, hard: 0, melt: smelt, meltTo: molten, smelt: 0.6, bag: true, desc: `Smelts at ${smelt}°C into ${name.toLowerCase()} and slag. ${o.oreNote || ''}` }); def(solid, { name, col, v: 8, k, cap: 1.5, hard: o.hardSolid || 3, melt, meltTo: molten, yld: scrap, desc }); def(molten, { name: 'Molten ' + name.toLowerCase(), ph: PH_LIQUID, col: mcol, v: 10, dens, k, cap: 1.5, hard: 0, freeze: melt - 5, freezeTo: solid, fluid: 0.7, spread: 20, liqT: melt + 70, bag: true, desc: `Sets into ${name.toLowerCase()} below ${melt - 5}°C.` }); def(scrap, { name: name + ' scrap', ph: PH_POWDER, col: col.map(c => c - 8), v: 32, dens: 5, k, cap: 1.5, hard: 0, stick: 0.7, melt, meltTo: molten, bag: true, desc: `${name} that set outside a mold. Melt it again and cast it.` }); def(bar, { name: name + ' bar', ph: PH_ITEM, col: col.map(c => Math.min(255, c + 12)), v: 0, dens, k: 0, hard: 0, melt, meltTo: molten, bag: true, desc: `A cast bar of ${name.toLowerCase()}.` }); } metalFamily({ vein: SNV, ore: SNORE, solid: TIN, molten: MSN, scrap: SCRSN, bar: BARSN, name: 'Tin', oreCol: [140, 156, 178], col: [196, 200, 206], mcol: [232, 234, 240], melt: 232, smelt: 1000, dens: 7, k: 0.03, hardVein: 3, hardSolid: 2, oreNote: 'Melt tin into molten copper to make bronze.', desc: 'Soft and silvery. Melts at only 232°C. Mixed into molten copper it makes bronze.' }); metalFamily({ vein: ZNV, ore: ZNORE, solid: ZINC, molten: MZN, scrap: SCRZN, bar: BARZN, name: 'Zinc', oreCol: [126, 100, 44], col: [166, 178, 190], mcol: [214, 224, 236], melt: 420, smelt: 1000, dens: 6.6, k: 0.03, hardVein: 4, oreNote: 'Melt zinc into molten copper to make brass.', desc: 'Bluish metal that melts at 420°C. Mixed into molten copper it makes brass.' }); metalFamily({ vein: AGV, ore: AGORE, solid: SILVER, molten: MAG, scrap: SCRAG, bar: BARAG, name: 'Silver', oreCol: [200, 204, 214], col: [214, 216, 224], mcol: [240, 236, 228], melt: 962, smelt: 962, dens: 9.3, k: 0.045, hardVein: 4, oreNote: 'Found deep in granite. Valuable even raw.', desc: 'A precious metal. Sells high.' }); metalFamily({ vein: AUV, ore: AUORE, solid: GOLD, molten: MAU, scrap: SCRAU, bar: BARAU, name: 'Gold', oreCol: [218, 182, 62], col: [232, 190, 72], mcol: [255, 214, 120], melt: 1064, smelt: 1064, dens: 17, k: 0.045, hardVein: 5, oreNote: 'The deepest and rarest ore. Sells for a fortune.', desc: 'The most valuable metal there is.' }); metalFamily({ solid: BRONZE, molten: MBZ, scrap: SCRBZ, bar: BARBZ, name: 'Bronze', col: [184, 126, 72], mcol: [255, 170, 90], melt: 950, dens: 8.7, k: 0.035, hardSolid: 4, desc: 'Copper with a little tin melted in. Harder than copper and worth far more.' }); metalFamily({ solid: BRASS, molten: MBS, scrap: SCRBS, bar: BARBS, name: 'Brass', col: [212, 174, 84], mcol: [255, 196, 104], melt: 930, dens: 8.4, k: 0.035, hardSolid: 4, desc: 'Copper with zinc melted in. Golden and valuable.' }); def(BARGL, { name: 'Glass brick', ph: PH_ITEM, col: [176, 218, 228], v: 0, dens: 2.5, k: 0, hard: 0, melt: 1300, meltTo: MGL, bag: true, desc: 'Cast from molten glass in an Ingot mold: 8 grains of glass. Sells well, and 2 make a glass wall block.' }); def(CUTST, { name: 'Cut stone', col: [168, 162, 150], v: 6, k: 0.012, hard: 4, melt: 1450, meltTo: MAGMA, yld: BARSB, desc: 'Dressed stone blocks laid in courses. Neater than rough stone, and it stands 200°C more heat before it slumps.' }); def(BARSB, { name: 'Stone brick', ph: PH_ITEM, col: [172, 166, 154], v: 0, dens: 2.6, k: 0, hard: 0, melt: 1450, meltTo: MAGMA, bag: true, desc: 'A block of stone cut square by a Stone cutter, from 8 grains of rubble. Builders buy them, and 2 make a cut stone wall block.' }); def(PIPE, { name: 'Pipe', col: [176, 112, 72], v: 4, k: 0.04, cap: 1.5, hard: 4, melt: 1085, meltTo: MCU, partMat: true }); def(DOCKW, { name: 'Trade dock', col: [70, 82, 96], v: 6, k: 0.01, cap: 2, hard: 9, yld: 0, partMat: true, desc: 'The claim office\'s trade dock. Whatever drops through the grate in its floor is sold.' }); def(HULL, { name: 'Machine', col: [84, 92, 102], v: 6, k: 0.03, cap: 1.5, hard: 4, melt: 1085, meltTo: MCU, partMat: true }); // Typed property tables const PH = new Uint8Array(NMAT), DENS = new Float32Array(NMAT), KC = new Float32Array(NMAT), ICAP = new Float32Array(NMAT), HARD = new Uint8Array(NMAT), YLD = new Uint8Array(NMAT), MELT = new Float32Array(NMAT), MELTTO = new Uint8Array(NMAT), SMELTP = new Float32Array(NMAT), FRZ = new Float32Array(NMAT), FRZTO = new Uint8Array(NMAT), BOIL = new Float32Array(NMAT), BOILTO = new Uint8Array(NMAT), CONDT = new Float32Array(NMAT), CONDTO = new Uint8Array(NMAT), IGN = new Float32Array(NMAT), FLAME = new Float32Array(NMAT), FLAMEF = new Float32Array(NMAT), FUEL = new Uint8Array(NMAT), BURNTO = new Uint8Array(NMAT), ASHP = new Float32Array(NMAT), FLUID = new Float32Array(NMAT), SPREAD = new Uint8Array(NMAT), STICK = new Float32Array(NMAT), ALPHA = new Float32Array(NMAT), LIQT = new Float32Array(NMAT), BAGOK = new Uint8Array(NMAT), PARTMAT = new Uint8Array(NMAT), RELAX = new Float32Array(NMAT), COLR = new Uint8Array(NMAT), COLG = new Uint8Array(NMAT), COLB = new Uint8Array(NMAT), CVAR = new Uint8Array(NMAT); for (let i = 0; i < NMAT; i++) { const d = MD[i]; PH[i] = d.ph; DENS[i] = d.dens; KC[i] = d.k; ICAP[i] = 1 / d.cap; HARD[i] = d.hard; YLD[i] = d.yld; MELT[i] = d.melt; MELTTO[i] = d.meltTo; SMELTP[i] = d.smelt; FRZ[i] = d.freeze; FRZTO[i] = d.freezeTo; BOIL[i] = d.boil; BOILTO[i] = d.boilTo; CONDT[i] = d.condT; CONDTO[i] = d.condTo; IGN[i] = d.ign; FLAME[i] = d.flame; FLAMEF[i] = d.flameF; FUEL[i] = d.fuel; BURNTO[i] = d.burnTo; ASHP[i] = d.ashP; FLUID[i] = d.fluid; SPREAD[i] = d.spread; STICK[i] = d.stick; ALPHA[i] = d.alpha; LIQT[i] = d.liqT; BAGOK[i] = d.bag ? 1 : 0; PARTMAT[i] = d.partMat ? 1 : 0; COLR[i] = d.col[0]; COLG[i] = d.col[1]; COLB[i] = d.col[2]; CVAR[i] = d.v; RELAX[i] = d.ph === PH_LIQUID ? 0.0006 : d.ph === PH_POWDER ? 0.0005 : d.ph === PH_GAS ? 0.003 : 0.0004; } // what molds cast (molten metals, and molten glass) and what they set into const CASTMETAL = new Uint8Array(NMAT); for (const m of [MCU, MFE, MST, MSN, MZN, MAG, MAU, MBZ, MBS, MGL]) CASTMETAL[m] = 1; // tier as a drill bit or tank (0: too soft to be a bit) const METAL_TIER = new Int8Array(NMAT).fill(-1); METAL_TIER[COPPER] = 1; METAL_TIER[IRON] = 2; METAL_TIER[STEEL] = 3; METAL_TIER[TIN] = 0; METAL_TIER[GLASS] = 0; METAL_TIER[ZINC] = 0; METAL_TIER[SILVER] = 0; METAL_TIER[GOLD] = 0; METAL_TIER[BRONZE] = 1; METAL_TIER[BRASS] = 1; const SOLIDMETAL = new Uint8Array(NMAT); for (const m of [COPPER, IRON, STEEL, TIN, ZINC, SILVER, GOLD, BRONZE, BRASS, GLASS]) SOLIDMETAL[m] = 1; // ---------- Flags & parts ---------- const F_NAT = 1, F_CAST = 2, F_BURN = 4; const P_NONE = 0, P_TU = 1, P_TD = 2, P_TL = 3, P_TR = 4, P_GRATE = 5, P_GOPEN = 6, P_WHEEL = 7, P_INTAKE = 8, P_FILTER = 9, P_PIPE = 10; const TDX = [0, 0, 0, -1, 1], TDY = [0, -1, 1, 0, 0]; // ---------- Tool tiers ---------- // reach: how far from the bot the drill works. Harder rock takes longer, and // every new bit cuts faster and further. const BIT_TIERS = [ { name: 'Stone bit', hard: 3, speed: 0.7, reach: 16 }, { name: 'Copper bit', hard: 4, speed: 1.0, reach: 24 }, { name: 'Iron bit', hard: 5, speed: 1.5, reach: 34 }, { name: 'Steel bit', hard: 6, speed: 2.2, reach: 46 }, ]; const TANK_TIERS = [ { name: 'Canvas sack', cap: 1500 }, { name: 'Copper tank', cap: 4000 }, { name: 'Iron tank', cap: 10000 }, { name: 'Steel tank', cap: 25000 }, ]; const REACH = 64;