// isokit/equipment: tanks, containers, generators, ground-mounted solar, // chimneys. fn meta_tank() { #{ label: "Tank", category: "Equipment", icon: "◯", props: [ #{ key: "r", type: "float", def: 2.0, min: 0.3, max: 30.0, step: 0.1, label: "Radius (m)" }, #{ key: "h", type: "float", def: 5.0, min: 0.5, max: 60.0, step: 0.1, label: "Height (m)" }, #{ key: "mat", type: "material", def: "tank", choices: ["tank", "water", "firetank", "steel", "silok", "siloy", "silor", "chiller"], label: "Colour" }, #{ key: "cap", type: "bool", def: true, label: "Cone roof" }, ] } } fn prefab_tank(o) { let p = o.p; let s = sprite(); s.cyl(0.0, 0.0, p.r, 0.0, p.h, p.mat); s.disc(0.0, 0.0, p.h * 0.6, p.r + 0.01, "tankring"); if p.cap { s.frust(0.0, 0.0, p.r, 0.25, p.h, p.h + p.r * 0.3, p.mat, 14); } } fn meta_container() { #{ label: "Shipping container", category: "Equipment", icon: "▭", props: [ #{ key: "size", type: "choice", def: "20ft", choices: ["10ft", "20ft", "40ft"], label: "Size" }, #{ key: "colour", type: "choice", def: "rack", choices: ["rack", "truckbox", "classic", "steel", "firewall"], label: "Colour" }, #{ key: "stack", type: "int", def: 1, min: 1, max: 4, step: 1, label: "Stacked" }, ] } } fn prefab_container(o) { let L = if o.p.size == "10ft" { 2.99 } else if o.p.size == "40ft" { 12.19 } else { 6.06 }; let s = sprite(); for i in 0..o.p.stack { s.box(-L / 2.0, -1.22, L / 2.0, 1.22, i * 2.59, (i + 1) * 2.59 - 0.02, o.p.colour); } } fn meta_generator() { #{ label: "Generator", category: "Equipment", icon: "⚡", props: [ #{ key: "running", type: "bool", def: false, label: "Running (exhaust)" }, ] } } fn prefab_generator(o) { let s = sprite(); s.box(-2.4, -1.1, 2.4, 1.1, 0.0, 0.25, "plinth"); s.box(-2.2, -0.95, 2.2, 0.95, 0.25, 2.4, "genset"); s.cyl(1.6, 0.4, 0.12, 2.4, 3.2, "stack"); if o.p.running { s.puffs(1.6, 0.4, 3.3, "smoke", 3, 3.2); } } fn meta_pv_field() { #{ label: "Solar field", category: "Equipment", icon: "▤", help: "Ground-mounted solar rows facing local -y.", props: [ #{ key: "w", type: "float", def: 20.0, min: 2.0, max: 500.0, step: 0.5, label: "Row length (m)" }, #{ key: "rows", type: "int", def: 4, min: 1, max: 60, step: 1, label: "Rows" }, #{ key: "pitch", type: "float", def: 4.0, min: 2.0, max: 12.0, step: 0.1, label: "Row spacing (m)" }, ] } } fn prefab_pv_field(o) { let p = o.p; let w = p.w / 2.0; let y0 = -(p.rows - 1) * p.pitch / 2.0; for i in 0..p.rows { // one sprite per row so trees and people sort between them let y = y0 + i * p.pitch; let s = sprite(); let n = (p.w / 4.0).ceiling().to_int(); for j in 0..(n + 1) { let x = -w + j * p.w / n; s.box(x - 0.05, y + 0.6, x + 0.05, y + 0.7, 0.0, 1.6, "steel"); } s.poly([[[-w, y - 1.0, 0.7], [w, y - 1.0, 0.7], [w, y + 1.0, 1.9], [-w, y + 1.0, 1.9]]], "pv"); } } fn meta_chimney() { #{ label: "Chimney / stack", category: "Equipment", icon: "▮", props: [ #{ key: "h", type: "float", def: 12.0, min: 2.0, max: 120.0, step: 0.5, label: "Height (m)" }, #{ key: "r", type: "float", def: 0.5, min: 0.1, max: 5.0, step: 0.05, label: "Radius (m)" }, #{ key: "smoke", type: "choice", def: "puff", choices: ["none", "puff", "puff2", "smoke"], label: "Plume" }, ] } } fn prefab_chimney(o) { let p = o.p; let s = sprite(); s.cyl(0.0, 0.0, p.r, 0.0, p.h, "stack"); s.cyl(0.0, 0.0, p.r * 1.05, p.h - 1.0, p.h - 0.6, "stackband", #{ no_top: true }); if p.smoke != "none" { s.puffs(0.0, 0.0, p.h + 0.3, p.smoke, 4, 4.0); } }