Comment: | complete (-ish) matter compiler UI (power drain still missing), add printable chemical light |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
3df08bd5acd80fe29755ad29b44b1aa4 |
User & Date: | lexi on 2024-05-06 16:20:04 |
Other Links: | manifest | tags |
2024-05-06
| ||
20:58 | add storage crate & generic interface for, add LED for print completion, add program tooltips, disfuckulate some longstanding idiot bugs check-in: 4b3aa092f8 user: lexi tags: trunk | |
16:20 | complete (-ish) matter compiler UI (power drain still missing), add printable chemical light check-in: 3df08bd5ac user: lexi tags: trunk | |
2024-05-05
| ||
19:31 | better alarm LEDs, continue work on matter compiler UI, hack around gravitational horrorscape (i.e. stop shitting all over the server's `minetest.conf`), better stat interface, tweak some compute stats, be more generous with starting battery loadout, mercilessly squash numberless bugs beneath my jackbooted heel check-in: 953151446f user: lexi tags: trunk | |
Modified mods/starlit-electronics/init.lua from [d82ba893dd] to [6d0114ddbf].
564 564 'blob'; -- opaque binary blob, so 3d-pty mods can use the 565 565 -- file mechanism to store arbirary data. 566 566 }; 567 567 drm = T.u8; -- inhibit copying 568 568 name = T.str; 569 569 body = T.text; 570 570 }, function(file) -- enc 571 + assert(E.chip.file[file.kind], string.format('invalid file kind "%s"', file.kind)) 571 572 local b = E.chip.file[file.kind].enc(file.body) 572 573 return { 573 574 kind = file.kind; 574 575 drm = file.drm; 575 576 name = file.name; 576 577 body = b; 577 578 } ................................................................................ 872 873 end; 873 874 __index = { 874 875 read = function(self) 875 876 local dat = E.chip.read(self.chip) 876 877 return dat.files[self.inode] 877 878 end; 878 879 write = function(self,data) 879 - -- print('writing', self.chip, self.inode) 880 880 return E.chip.fileWrite(self.chip, self.inode, data) 881 881 end; 882 882 erase = function(self) 883 883 local dat = E.chip.read(self.chip) 884 884 table.remove(dat.files, self.inode) 885 885 E.chip.write(self.chip, dat) 886 886 self.inode = nil ................................................................................ 909 909 then 910 910 for fl, inode in E.chip.files(e) do 911 911 if fl.kind == 'sw' then 912 912 local s = starlit.item.sw.db[fl.body.pgmId] 913 913 table.insert(sw, { 914 914 sw = s, chip = e, chipSlot = i; 915 915 file = fl, inode = inode; 916 + id = fl.body.pgmId; 916 917 }) 917 918 end 918 919 end 919 920 end 920 921 end 921 922 end 922 923 923 924 for _, s in pairs(sw) do 924 925 if s.sw.cost.ram <= comp.ram and pred(s) then 925 926 table.insert(r, { 927 + id = s.id; 926 928 sw = s.sw; 927 929 chip = s.chip, chipSlot = s.chipSlot; 928 930 file = s.file; 929 931 fd = E.chip.fileHandle(s.chip, s.inode); 930 932 speed = s.sw.cost.cycles / comp.cycles; 931 933 powerCost = s.sw.cost.cycles / comp.powerEfficiency; 932 934 comp = comp;
Modified mods/starlit-electronics/sw.lua from [da2672ba3c] to [1f9bdf2a9e].
133 133 cost = { 134 134 cycles = 100e6; 135 135 ram = 500e6; 136 136 }; 137 137 run = shredder{range=3, powerDraw=200}; 138 138 }) 139 139 140 -starlit.item.sw.link('starlit_electronics:compile_commune', { 140 +local function matterCompiler(desc) 141 + return { 142 + name = desc.name; 143 + kind = 'suitPower', powerKind = 'direct'; 144 + desc = desc.desc; 145 + size = desc.size; 146 + cost = desc.cost; 147 + ui = 'starlit:compile-matter-component'; 148 + bgProc = function(user, ctx, interval, runState) 149 + if runState.flags.compiled == true then return false end 150 + -- only so many nanides to go around 151 + runState.flags.compiled = true 152 + 153 + local conf = ctx.file.body.conf 154 + local job_t = starlit.store.compilerJob 155 + local job, jobSlot 156 + for i, v in ipairs(conf) do 157 + if v.key == 'job' then 158 + job = job_t.dec(v.value) 159 + jobSlot = i 160 + goto found 161 + end 162 + end 163 + 164 + ::notfound:: do 165 + return 166 + end 167 + 168 + ::found:: 169 + local scm = starlit.item.sw.db[job.schematic] 170 + job.cyclesLeft = math.max(0, job.cyclesLeft - ctx.comp.cycles) 171 + if job.cyclesLeft == 0 then 172 + job.timeLeft = math.max(0, job.timeLeft - interval) 173 + end 174 + if job.timeLeft == 0 and job.cyclesLeft == 0 then 175 + table.remove(conf, jobSlot) 176 + user:give(scm.output) 177 + else 178 + conf[jobSlot].value = job_t.enc(job) 179 + end 180 + 181 + ctx.saveConf() 182 + end; 183 + } 184 +end 185 + 186 +starlit.item.sw.link('starlit_electronics:compile_commune', matterCompiler { 141 187 name = 'Compile Matter'; 142 - kind = 'suitPower', powerKind = 'direct'; 143 188 desc = "A basic suit matter compiler program. It's rather slow, but it's been ruthlessly optimized for size- and memory-efficiency by some of the Commune's most fanatic coders, to the point where every Commune nanosuit can come with the program preinstalled."; 144 189 size = 700e3; 145 190 cost = { 146 191 cycles = 4e9; 147 192 ram = .3e9; 148 193 }; 149 - ui = 'starlit:compile-matter-component'; 150 - run = function(user, ctx) 151 - end; 152 194 }) 153 195 154 196 starlit.item.sw.link('starlit_electronics:compile_block_commune', { 155 197 name = 'Compile Block'; 156 198 kind = 'suitPower', powerKind = 'active'; 157 199 desc = "An advanced suit matter compiler program, capable of printing complete devices and structure parts directly into the world."; 158 200 size = 5e6; ................................................................................ 161 203 ram = 1e9; 162 204 }; 163 205 ui = 'starlit:compile-matter-block'; 164 206 run = function(user, ctx) 165 207 end; 166 208 }) 167 209 168 -starlit.item.sw.link('starlit_electronics:compile_imperial', { 210 +starlit.item.sw.link('starlit_electronics:compile_imperial', matterCompiler { 169 211 name = 'Genesis Deluxe'; 170 - kind = 'suitPower', powerKind = 'direct'; 171 212 desc = "House Bascundir has long dominated the matter compiler market in the Crystal Sea. Their firmware is excessively complex due to mountains of specialized edge-case handling, but the end result is certainly speedier than the competitors'."; 172 213 size = 2e4; 173 214 cost = { 174 215 cycles = 100e6; 175 216 ram = 1.5e9; 176 217 }; 177 - ui = 'starlit:compile-matter-component'; 178 - run = function(user, ctx) 179 - end; 180 218 }) 181 219 182 220 do local J = starlit.store.compilerJob 183 221 starlit.item.sw.link('starlit_electronics:driver_compiler_commune', { 184 222 name = 'Matter Compiler'; 185 223 kind = 'driver'; 186 224 desc = "A driver for a standalone matter compiler, suitable for building larger components than your suit alone can handle."; ................................................................................ 188 226 cost = { 189 227 cycles = 400e6; 190 228 ram = .2e9; 191 229 }; 192 230 ui = 'starlit:device-compile-matter-component'; 193 231 run = function(user, ctx) 194 232 end; 233 + --[[ 195 234 bgProc = function(user, ctx, interval, runState) 196 235 if runState.flags.compiled == true then return false end 197 236 -- only so many nanides to go around 198 237 runState.flags.compiled = true 199 238 local time = minetest.get_gametime() 200 239 local cyclesLeft = ctx.comp.cycles * interval 201 240 ................................................................................ 232 271 else 233 272 e.value = J.enc(t) 234 273 end 235 274 if not cyclesLeft > 0 then break end 236 275 end 237 276 end 238 277 ctx.saveConf() 239 - end; 278 + end;]] 240 279 }) 241 280 end 242 281 243 282 local function pasv_heal(effect, energy, lvl, pgmId) 244 283 return function(user, ctx, interval, runState) 245 284 if runState.flags.healed == true then return false end 246 285 -- competing nanosurgical programs?? VERY bad idea
Modified mods/starlit-material/elements.lua from [fb5dcf0ef1] to [81b3a1522a].
40 40 color = lib.color(1,.8,0.1); 41 41 }; 42 42 calcium = { 43 43 name = 'calcium', sym = 'Ca', n = 20; density = 1.55; 44 44 metal = true; 45 45 color = lib.color(1,1,0.7); 46 46 }; 47 + magnesium = { 48 + name = 'magnesium', sym = 'Mg', n = 12, density = 1.738; 49 + metal = true; 50 + color = lib.color(0.7, 0.7, 0.7); 51 + }; 47 52 aluminum = { 48 53 name = 'aluminum', sym = 'Al', n = 13; density = 2.7; 49 54 metal = true; 50 - color = lib.color(0.9,.95,1); 55 + color = lib.color(0.5,.55,.6); 51 56 }; 52 57 iron = { 53 58 name = 'iron', sym = 'Fe', n = 26; density = 7.874; 54 59 metal = true; 55 60 color = lib.color(.3,.3,.3); 56 61 }; 57 62 copper = {
Modified mods/starlit-scenario/init.lua from [a805932fc9] to [98f93d94ac].
42 42 {'starlit_electronics:shred', 0}; 43 43 --{'starlit_electronics:compile_empire', 0}; 44 44 {'starlit_electronics:autodoc_deluxe', 1}; 45 45 --{'starlit_electronics:driver_compiler_empire', 0}; 46 46 }); 47 47 survivalware = makeChip('Emergency Survivalware', { 48 48 {'starlit_electronics:battery_chemical_commune_small', 0}; 49 + {'starlit_tech:chem_lamp', 0}; 49 50 }, { 50 51 {'starlit_electronics:shred', 0}; 51 52 {'starlit_electronics:compile_commune', 0}; 52 53 {'starlit_electronics:nanomed', 0}; 53 54 {'starlit_electronics:driver_compiler_commune', 0}; 54 55 }); 55 56 misfortune = makeChip("Sold1er0fMisf0rtune TOP Schematic Crackz REPACK", {
Added mods/starlit-tech/init.lua version [2a09a8ef6e].
1 +local lib = starlit.mod.lib 2 + 3 + 4 +do -- chemlamp 5 + local burnTime = 60*60 6 + local maxBright = 12 7 + local stages = maxBright 8 + local stageTimeout = burnTime / stages 9 + local function chemLampID(n) 10 + if n == stages then return 'starlit_tech:chem_lamp' end 11 + return string.format('starlit_tech:chem_lamp_%s',n) 12 + end 13 + local fab = starlit.type.fab { 14 + element = { carbon = 8, magnesium = 2 }; 15 + cost = { power = 100 }; 16 + flag = { print = true }; 17 + time = { print = 5 }; 18 + reverseEngineer = { 19 + complexity = 1; 20 + sw = 'starlit_tech:schematic_chem_lamp'; 21 + }; 22 + }; 23 + for i = stages, 0, -1 do 24 + minetest.register_node(chemLampID(i), { 25 + short_description = 'Chem Lamp'; 26 + description = starlit.ui.tooltip { 27 + title = 'Chem Lamp'; 28 + desc = "A simple carbon-frame chemical light source powered by ambient oxygen. Cheap, quick to print, and biodedragable, without any need for an electric grid or complex power storage mechanism. However, the light only lasts a few days, after which the lamp must be recycled or discarded."; 29 + color = lib.color(1,.4,.1); 30 + props = { 31 + {title = 'Burn Remaining', desc=lib.math.timespec(stageTimeout * i), affinity=i > 4 and 'good' or 'bad'}; 32 + {title = 'Mass', desc='10g', affinity='info'}; 33 + }; 34 + }; 35 + drawtype = 'nodebox'; 36 + groups = { 37 + object = 2; 38 + attached_node = 1; 39 + }; 40 + node_box = { 41 + type = 'fixed'; 42 + fixed = { 43 + -.4, -.5, -.20; 44 + .4, -.3, .20; 45 + }; 46 + }; 47 + tiles = { 48 + lib.image 'starlit-tech-lamp-glow.png' 49 + :fade(1 - i/stages) 50 + :blit(lib.image 'starlit-tech-lamp.png') 51 + :render(); 52 + }; 53 + paramtype = 'light'; 54 + paramtype2 = 'wallmounted'; 55 + wallmounted_rotate_vertical = true; 56 + light_source = math.floor(lib.math.lerp(i/stages, 0, maxBright)); 57 + on_construct = i ~= 0 and function(pos) 58 + local t = minetest.get_node_timer(pos) 59 + t:start(stageTimeout) 60 + end or nil; 61 + on_timer = i ~= 0 and function(pos) 62 + local me = minetest.get_node(pos) 63 + minetest.swap_node(pos, {name=chemLampID(i-1), param2=me.param2}) 64 + return i > 1 65 + end or nil; 66 + _starlit = { 67 + mass = 10; 68 + fab = fab; 69 + recover = starlit.type.fab { 70 + element = { 71 + carbon = 8; 72 + magnesium = math.floor(lib.math.lerp(i/stages, 0, 2)); 73 + }; 74 + time = { 75 + shred = .5; 76 + shredPower = 2; 77 + }; 78 + }; 79 + 80 + }; 81 + }) 82 + end 83 + starlit.item.sw.link('starlit_tech:schematic_chem_lamp', { 84 + name = 'Chem Lamp Schematic'; 85 + kind = 'schematic'; 86 + input = fab; 87 + output = chemLampID(stages); 88 + size = 32e6; 89 + cost = { 90 + cycles = 8e9; 91 + ram = 16e6; 92 + }; 93 + rarity = 1; 94 + }) 95 +end
Added mods/starlit-tech/mod.conf version [4aaf988ed1].
1 +name = starlit_tech 2 +title = starlit tech 3 +depends = vtlib, starlit, starlit_material, starlit_electronics
Added mods/starlit/compile.lua version [8a9b22510e].
1 +local lib = starlit.mod.lib 2 + 3 +local recentJobs do 4 + local T,G = lib.marshal.t, lib.marshal.g 5 + recentJobs = G.array(8, T.str) 6 +end 7 +local function getRecentJobs(state) 8 + for i,v in ipairs(state.pgm.file.body.conf) do 9 + if v.key == 'recent' then 10 + return recentJobs.dec(v.value), i 11 + end 12 + end 13 + return {} 14 +end 15 + 16 +local function buyPrintJob(state, invs, cost, scm) 17 + -- consume consumables 18 + -- FIXME handle cost.leftovers from partially-consumed items 19 + for _, v in pairs(cost.consume) do 20 +-- assert(v.inv == 1, 'impossible condition (wrong inventory ID)') 21 + local i = invs[v.inv] 22 + i.hnd:set_stack(i.list, v.slot, v.remain) 23 + end 24 + local output = ItemStack(scm.sw.output):get_definition() 25 + local fab = scm.sw.input 26 + 27 + local job_t = starlit.store.compilerJob 28 + local conf = state.pgm.file.body.conf 29 + table.insert(conf, { 30 + key='job', value=job_t.enc { 31 + schematic = scm.id; 32 + cyclesLeft = scm.sw.cost and scm.sw.cost.cycles or 0; 33 + timeLeft = (fab.time and fab.time.print or 0); 34 + } 35 + }) 36 +end 37 + 38 +local function compilerCanPrint(user, cpl, scm) 39 + local E = starlit.mod.electronics 40 + local output = ItemStack(scm.sw.output):get_definition() 41 + local fab = scm.sw.input 42 + local sw = scm.sw 43 + local ok, consume, unsat, leftover, itemSpec = fab:seek { 44 + user.entity:get_inventory():get_list 'main'; 45 + } 46 + 47 + local cost = { 48 + fab = fab, output = output; 49 + consume = consume, unsat = unsat, leftover = leftover, itemSpec = itemSpec; 50 + runtimeEstimate = scm.speed + cpl.speed + (fab.time and fab.time.print or 0); 51 + power = cpl.powerCost + scm.powerCost; 52 + ram = (cpl.cost and cpl.cost.ram or 0) 53 + + (scm.cost and scm.cost.ram or 0); 54 + cycles = (cpl.cost and cpl.cost.cycles or 0) 55 + + (scm.cost and scm.cost.cycles or 0); 56 + } 57 + 58 + local userComp = E.chip.sumCompute( 59 + user.entity:get_inventory():get_list 'starlit_suit_chips' 60 + ) 61 + 62 + if ok and cost.power <= user:suitCharge() and cost.ram <= userComp.ram then 63 + return true, cost 64 + else return false, cost end 65 +end 66 + 67 +starlit.alg.compilerCanPrint = compilerCanPrint 68 + 69 +-- TODO destroy suit interfaces when power runs out or suit/chip is otherwise disabled 70 +starlit.interface.install(starlit.type.ui { 71 + id = 'starlit:compile-matter-component'; 72 + sub = { 73 + suit = function(state, user, evt) 74 + if evt.kind == 'disrobe' then state:close() 75 + elseif evt.kind == 'power' and evt.mode == 'off' then state:close() end 76 + end; 77 + playerInventory = function(state,user) 78 + -- refresh 79 + end; 80 + }; 81 + pages = { 82 + index = { 83 + setupState = function(state, user, ctx) 84 + local E = starlit.mod.electronics 85 + state.pgm = ctx.program 86 + state.ctx = ctx 87 + state.select = {} 88 + if ctx.context == 'suit' then 89 + state.fetch = function() 90 + local cst = user.entity:get_inventory():get_list 'starlit_suit_chips' 91 + local cl = {order={}, map={}, slot={}} 92 + for i, c in ipairs(cst) do 93 + if not c:is_empty() then 94 + local d = E.chip.read(c) 95 + local co = { 96 + stack = c; 97 + data = d; 98 + } 99 + table.insert(cl.order, co) 100 + cl.map[d.uuid] = co 101 + cl.slot[i] = co 102 + end 103 + end 104 + 105 + -- kill me fam 106 + if ( state.select.chip 107 + and state.select.chip ~= true 108 + and not cl.map[state.select.chip]) 109 + or (state.select.scm 110 + and not state.select.scms[state.select.scm]) 111 + then 112 + -- chip or pgm no longer available 113 + user:suitSound 'starlit-error' 114 + state.select = {} 115 + end 116 + state.select.chips = cl 117 + 118 + state.select.scms = {} 119 + if state.select.chip then 120 + state.select.scms = E.chip.usableSoftware(cst,nil, function(s) 121 + if state.select.chip ~= true then 122 + if cl.slot[s.chipSlot].data.uuid ~= state.select.chip then 123 + return false 124 + end 125 + end 126 + return s.sw.kind == 'schematic' 127 + end) 128 + end 129 + 130 + end 131 + end 132 + end; 133 + 134 + onClose = function(state, user) 135 + user:suitSound 'starlit-quit' 136 + end; 137 + refresh = true; 138 + handle = function(state, user, q) 139 + local E = starlit.mod.electronics 140 + if not state.ctx.verify() then state.close() end 141 + local inv = user.entity:get_inventory() 142 + 143 + local sel = state.select 144 + state.fetch() 145 + local chips = state.select.chips 146 + local function chirp() 147 + user:suitSound 'starlit-nav' 148 + end 149 + 150 + -- are we signalling a reprint? 151 + for k in next, q do 152 + local idx = k:match'^recent_(%d+)$' 153 + if idx then 154 + local jobs = getRecentJobs(state) 155 + local scmid = jobs[tonumber(idx)] 156 + if not scmid then return false end 157 + -- get list of available schematics and make sure this is on it 158 + local cst = inv:get_list 'starlit_suit_chips' 159 + local all = E.chip.usableSoftware(cst, nil, function(s) 160 + return s.sw.kind == 'schematic' 161 + end) 162 + local scm 163 + for i, s in ipairs(all) do 164 + if s.id == scmid then scm = s goto found end 165 + end 166 + 167 + ::fail:: do 168 + user:suitSound 'starlit-error' 169 + return false 170 + end 171 + 172 + ::found:: 173 + local ok,cost = compilerCanPrint(user, state.pgm, scm) 174 + if not ok then goto fail end 175 + user:suitSound 'starlit-configure' 176 + buyPrintJob(state, {{hnd=inv,list='main'}}, cost, scm) 177 + state.ctx.saveConf() 178 + return true 179 + end 180 + end 181 + 182 + local function trySelection(id) 183 + if sel[id] == nil then 184 + for k in next, q do 185 + local pat = "^"..id.."_(%d+)$" -- ew 186 + local idx = k:match(pat) 187 + if idx then 188 + local cm = tonumber(idx) 189 + if cm then 190 + chirp() 191 + sel[id] = cm 192 + return true 193 + end 194 + end 195 + end 196 + end 197 + end 198 + 199 + if sel.chip == nil then 200 + if q.showAll then 201 + chirp() 202 + sel.chip = true 203 + return true 204 + elseif q.find then 205 + chirp() 206 + -- TODO 207 + return true 208 + end 209 + end 210 + 211 + if trySelection('chip') then 212 + return true 213 + elseif trySelection('scm') then 214 + return true 215 + else 216 + if q.back then 217 + chirp() 218 + if sel.input then 219 + sel.input = nil 220 + elseif sel.scm then 221 + sel.scm = nil 222 + elseif sel.chip then 223 + sel.chip = nil 224 + end 225 + return true 226 + elseif q.commit then 227 + if not sel.input then 228 + chirp() 229 + sel.input = true 230 + return true 231 + else 232 + local scm = sel.scms[sel.scm] 233 + local ok, cost = compilerCanPrint(user, state.pgm, scm) 234 + if ok then 235 + user:suitSound 'starlit-configure' 236 + 237 + buyPrintJob(state, {{hnd=inv,list='main'}}, cost, scm) 238 + 239 + -- add recent print 240 + local rctList, pairIdx = getRecentJobs(state) 241 + if #rctList >= 30 then 242 + table.remove(rctList) 243 + end 244 + 245 + if not lib.tbl.has(rctList, scm.id) then 246 + table.insert(rctList,1,scm.id) 247 + end 248 + 249 + local conf = state.pgm.file.body.conf 250 + local encoded = recentJobs.enc(rctList) 251 + if pairIdx then 252 + conf[pairIdx].value = encoded 253 + else 254 + table.insert(conf, {key='recent', value=encoded}) 255 + end 256 + 257 + -- write chip 258 + state.ctx.saveConf() 259 + -- clear selection 260 + state.select = {} 261 + return true 262 + else 263 + user:suitSound 'starlit-error' 264 + end 265 + end 266 + end 267 + end 268 + 269 + end; 270 + 271 + render = function(state, user) 272 + local sel, pgmSelector = state.select, {} 273 + state.fetch() 274 + state.ctx.pullConf() 275 + 276 + local function pushSelector(id, item, label, desc, req) 277 + local rh = .5 278 + local label = {kind = 'text', w = 10-1.5, h=1.5; 279 + text = '<global valign=middle>'..lib.str.htsan(label) } 280 + if req then 281 + label.h = label.h - rh - .2 282 + 283 + local imgs = {} 284 + for ci,c in ipairs(req) do 285 + for ei, e in ipairs(c.list) do 286 + table.insert(imgs, {kind = 'img', w=rh, h=rh, img=e.img}) 287 + end 288 + end 289 + label = {kind = 'vert', w = 10-1.5, h=1.5; 290 + label; 291 + {kind ='hztl', w=10-1.5, h=rh; unpack(imgs); } 292 + } 293 + end 294 + table.insert(pgmSelector, {kind = 'hztl', w=10,h=1.5; 295 + {kind = 'contact', id=id, w=1.5, h=1.5; 296 + item = item; 297 + color = {hue=220, sat=0, lum=0}; 298 + desc = desc; 299 + }; 300 + label; 301 + }) 302 + end 303 + 304 + local back = {kind = 'button', id='back', label = '<- Back', w=10,h=1.2} 305 + if sel.chips == nil then 306 + table.insert(pgmSelector, {kind = 'img', img = 'starlit-ui-alert.png', w=2, h=2}) 307 + elseif sel.chip == nil then 308 + for i, c in ipairs(sel.chips.order) do 309 + -- TODO filter out chips without schematics? 310 + pushSelector('chip_' .. c.data.uuid, c.stack, c.data.label) 311 + end 312 + if next(sel.chips.order) then 313 + table.insert(pgmSelector, {kind = 'hztl', w=10,h=1.5; 314 + {kind = 'button', w=5,h=1.5; id='showAll', label='Show All'}; 315 + {kind = 'button', w=5,h=1.5; id='find', label='Find'}; 316 + }) 317 + end 318 + else 319 + if sel.scm == nil then 320 + for idx, ent in ipairs(sel.scms) do 321 + local fab = ItemStack(ent.sw.output):get_definition()._starlit.fab 322 + if fab.flag and fab.flag.print then 323 + local req = fab:visualize() 324 + pushSelector('scm_' .. idx, ent.sw.output, ent.sw.name, nil, req) 325 + end 326 + end 327 + table.insert(pgmSelector, back) 328 + else 329 + local scm = sel.scms[sel.scm] 330 + local output = ItemStack(scm.sw.output):get_definition() 331 + local fab = scm.sw.input 332 + local sw = scm.sw 333 + local function unmet(str) 334 + return lib.color(1,.3,.3):fmt(str) 335 + end 336 + table.insert(pgmSelector, {kind = 'hztl', w=10, h=1.2; 337 + {kind = 'img', item = sw.output, w=1.2, h=1.2, desc=output.description}; 338 + {kind = 'text', text = string.format('<global valign=middle><b>%s</b>', lib.str.htsan(sw.name)), w=10-1.2,h=1.2}; 339 + }) 340 + local inputTbl = {kind = 'vert', w=5,h=0; 341 + {kind = 'hbar', w=5, h=.5, text=sel.input and 'Input Plan' or 'Input'}}; 342 + local costTbl = {kind = 'vert', w=5,h=0; 343 + {kind = 'hbar', w=5, h=.5, text=sel.input and 'Process Plan' or 'Process'}}; 344 + local reqPane = {kind = 'pane', id='reqPane', w=10, h=7; 345 + {kind = 'hztl', w=10,h=0; inputTbl, costTbl} 346 + } 347 + local function pushCost(x, t, val) 348 + table.insert(costTbl, {kind='label', w=4.5,h=.5,x=x; 349 + text=string.format('%s: %s',t,val); 350 + }) 351 + end 352 + local function pushComputeCosts(header, p) 353 + if p then 354 + table.insert(costTbl, {kind = 'label', w=5, h=.5, x=0; text=header}); 355 + if p.cycles then 356 + pushCost(.5, 'Compute', lib.math.siUI({'cycle','cycles'}, p.cycles, true)) 357 + end 358 + if p.power then 359 + local str = lib.math.siUI('J', p.power) 360 + if p.power > user:suitCharge() then str = unmet(str) end 361 + pushCost(.5, 'Power', str) 362 + end 363 + if p.ram then 364 + local str = string.format("%s / %s", 365 + lib.math.siUI('B', p.ram), 366 + lib.math.siUI('B', state.pgm.comp.ram)) 367 + if p.ram > state.pgm.comp.ram then str = unmet(str) end 368 + pushCost(.5, 'Memory', str) 369 + end 370 + end 371 + end 372 + 373 + local function fabToUI(x, inputTbl, req) 374 + for ci,c in ipairs(req) do 375 + table.insert(inputTbl, {kind = 'label', w=5-x, h=.5, x=x; 376 + text=lib.str.capitalize(c.header)}); 377 + for ei,e in ipairs(c.list) do 378 + table.insert(inputTbl, {kind = 'hztl', w=4.5-x, h=.5, x=x+.5; 379 + {kind='img', w=.5,h=.5, img=e.img}; 380 + {kind='label', w=3.3,h=.5,x=.2, text=lib.str.capitalize(e.label)}; 381 + }); 382 + end 383 + end 384 + end 385 + 386 + local commitHue, commitLabel = 120 387 + if not sel.input then 388 + commitLabel = 'Plan' 389 + fabToUI(0, inputTbl, fab:visualize()) 390 + local function pushComputeCostsSw(header, p) 391 + if p.sw.cost then 392 + pushComputeCosts(header, { 393 + cycles = p.sw.cost.cycles; 394 + power = p.powerCost; 395 + ram = p.sw.cost.ram; 396 + }) 397 + end 398 + end 399 + pushComputeCostsSw('Schematic', scm) 400 + pushComputeCostsSw('Compiler', state.pgm) 401 + else 402 + commitLabel = 'Commit' 403 + pushComputeCosts('Total', { 404 + cycles = (scm.sw.cost and scm.sw.cost.cycles or 0) 405 + + (state.pgm.sw.cost and state.pgm.sw.cost.cycles or 0); 406 + power = (scm.powerCost or 0) 407 + + (state.pgm.powerCost or 0) 408 + + (fab.cost and fab.cost.power or 0); 409 + ram = (scm.sw.cost and scm.sw.cost.ram or 0) 410 + + (state.pgm.sw.cost and state.pgm.sw.cost.ram or 0); 411 + }) 412 + if fab.time and fab.time.print then 413 + pushCost(0, 'Job Runtime', lib.math.timespec(fab.time.print + scm.speed)) 414 + pushCost(.5, 'Print Time', lib.math.timespec(fab.time.print)) 415 + pushCost(.5, 'CPU Time', lib.math.timespec(scm.speed + state.pgm.speed)) 416 + end 417 + local ok, compileCost = compilerCanPrint(user, state.pgm, scm) 418 + fabToUI(0, inputTbl, compileCost.itemSpec:visualize()) 419 + 420 + if next(compileCost.unsat) then 421 + local vis = compileCost.unsat:visualize() 422 + for si, s in ipairs(vis) do 423 + s.header = 'Missing ' .. s.header 424 + for ei, e in ipairs(s.list) do 425 + e.label = lib.color(1,.2,.2):fmt(e.label) 426 + end 427 + end 428 + fabToUI(0, inputTbl, vis) 429 + end 430 + if not ok then commitHue = 0 end 431 + end 432 + table.insert(pgmSelector, reqPane) 433 + table.insert(pgmSelector, {kind = 'hztl', w=10,h=1.2; 434 + {kind = 'button', id='back', label = '← Back', w=5,h=1.2}; 435 + {kind = 'button', id='commit', label = commitLabel .. ' →', w=5,h=1.2, color={hue=commitHue,sat=0,lum=0}}; 436 + }) 437 + end 438 + end 439 + 440 + local rec = getRecentJobs(state) 441 + local recentList = {kind = 'hwrap', cols=3} 442 + if rec then 443 + for i,id in ipairs(rec) do 444 + local out = ItemStack(starlit.item.sw.db[id].output) 445 + table.insert(recentList, {kind='contact',w=1.5,h=1.5,id=string.format('recent_%s',i), item = out}) 446 + end 447 + end 448 + local queue = {kind='pane', w=5, h=9.5} 449 + for i,v in ipairs(state.pgm.file.body.conf) do 450 + if v.key == 'job' then 451 + local job = starlit.store.compilerJob.dec(v.value) 452 + local scm = starlit.item.sw.db[job.schematic] 453 + local cycTotal = (scm.cost and scm.cost.cycles or 0) 454 + local secTotal = (scm.input.time and scm.input.time.print or 0) 455 + local cycPct = cycTotal == 0 and 1 or (1 - job.cyclesLeft/cycTotal) 456 + local secPct = secTotal == 0 and 1 or (1 - job.timeLeft/secTotal) 457 + local out = ItemStack(scm.output) 458 + local cycBar = {kind = 'hbar', fac = cycPct, w=5-1.5, h = .5; 459 + color={hue=150,sat=0,lum=0}; text=string.format("Compute %s%%", math.floor(cycPct*100)); 460 + } 461 + local secBar = {kind = 'hbar', fac = secPct, w=5-1.5, h = .5; 462 + color={hue=50,sat=0,lum=0}; text=string.format("Assemble %s%%", math.floor(secPct*100)); 463 + } 464 + table.insert(queue, {kind='hztl'; w=5, h=1.5; 465 + {kind = 'contact', w=1.5,h=1.5, id=string.format('cancel_%s', i), item = out}; 466 + {kind = 'vert', w=5-1.5, h=1.5; 467 + {kind = 'label', text=out:get_definition().short_description, w=5-1.5, h=.75}; 468 + (cycPct < 1 and cycBar or secBar); 469 + } 470 + }) 471 + end 472 + end 473 + 474 + return starlit.ui.build { 475 + kind = 'hztl', padding = 0.5; w = 20, h = 10, mode = 'sw'; 476 + {kind = 'vert', w = 5, h = 5; 477 + {kind = 'hbar', fac=0, w = 5, h = .5, text = '<b><left>Recent Prints</left></b>'}; 478 + recentList; 479 + }; 480 + {kind = 'vert', w = 10, h = 10; 481 + {kind = 'hbar', fac=0, w = 10, h = .5, text = '<b>Program Select</b>'}; 482 + {kind = 'pane', w = 10, h = 9.5, id='pgmSelect'; 483 + unpack(pgmSelector) 484 + }; 485 + }; 486 + {kind = 'vert', w = 5, h = 10; 487 + {kind = 'hbar', fac=0, w = 5, h = .5, text = '<b><right>Print Queue</right></b>'}; 488 + queue; 489 + }; 490 + } 491 + end; 492 + }; 493 + }; 494 +})
Modified mods/starlit/fab.lua from [a2443e45a4] to [f85992f960].
102 102 end; 103 103 image = function(x, n) 104 104 return string.format('starlit-element-%s.png', x) 105 105 end; 106 106 inventory = fRawMat 'element'; 107 107 op = fQuant; 108 108 }; 109 - metal ={ 109 + metal = { 110 110 name = {"metal", "metals"}; 111 111 string = function(x, n) 112 112 local met = starlit.world.material.metal.db[x] 113 113 return lib.math.siUI('g', n) .. ' ' .. met.name 114 114 end; 115 115 image = function(x, n) 116 116 local met = starlit.world.material.metal.db[x] ................................................................................ 333 333 if not alreadyGot(ii,oi) then 334 334 local sv = { 335 335 inv=ii, slot=oi; 336 336 consume=deduct, remain=st; 337 337 satisfy=fab{[cat]={[substance]=avail}} 338 338 } 339 339 table.insert(stacks, sv) 340 + table.insert(consumed, sv) 340 341 end 341 342 if amtFound >= amt then goto suffice end 342 343 end 343 344 end 344 345 end 345 346 end 346 347
Modified mods/starlit/init.lua from [aee56c43bb] to [a5bde19f07].
54 54 }; 55 55 56 56 interface = lib.registry.mk 'starlit:interface'; 57 57 item = { 58 58 food = lib.registry.mk 'starlit:food'; 59 59 seed = lib.registry.mk 'starlit:seed'; 60 60 }; 61 + 62 + -- complex algorithms that cut across namespaces or don't belong anywhere else 63 + alg = {}; 61 64 62 65 region = { 63 66 radiator = { 64 67 store = AreaStore(); 65 68 emitters = {}; 66 69 }; 67 70 }; ................................................................................ 275 278 276 279 starlit.include 'fx/nano' 277 280 278 281 starlit.include 'element' 279 282 280 283 starlit.include 'terrain' 281 284 starlit.include 'interfaces' 285 +starlit.include 'compile' 282 286 starlit.include 'suit' 283 287 284 288 -- minetest.settings:set('movement_gravity', starlit.world.planet.gravity) -- ??? seriously??? 285 289 -- THIS OVERRIDES THE GLOBAL SETTING *AND PERSISTS IT* WHAT IN THE SATANIC FUCK 286 290 287 291 --------------- 288 292 -- callbacks -- ................................................................................ 321 325 return starlit.ui.userMenuDispatch(user,fields) 322 326 end 323 327 local ui = starlit.interface.db[formid] 324 328 local state = starlit.activeUI[name] or {} 325 329 if formid == '__builtin:help_cmds' 326 330 or formid == '__builtin:help_privs' 327 331 then return false end 328 - assert(state.form == formid) -- sanity check 332 + if not (state.form == formid) then -- sanity check 333 + log.warn('user %s attempted to send form %s while %s was active', name, formid, state.form) 334 + return false 335 + end 329 336 user:onRespond(ui, state, fields) 330 337 if fields.quit then 331 338 starlit.activeUI[name] = nil 332 339 end 333 340 return true 334 341 end) 335 342 ................................................................................ 392 399 }) 393 400 minetest.register_item("starlit:_hand_dig", { 394 401 type = "none", 395 402 wield_image = "wieldhand.png", 396 403 wield_scale = {x=1,y=1,z=2.5}, 397 404 tool_capabilities = { 398 405 groupcaps = { 406 + object = {maxlevel=1, times = {.20,.10}}; 399 407 plant = {maxlevel=1, times = {.50}}; 400 408 401 409 -- sand, dirt, gravel 402 410 looseClump = {maxlevel=1, times = {1.5, 2.5}}; 403 411 }; 404 412 } 405 413 })
Modified mods/starlit/interfaces.lua from [c1a1690c3b] to [ddaa1e9478].
12 12 img='starlit-ui-icon-nano.png', close=true, color = cmode'nano'}; 13 13 {kind = 'contact', w=1.5,h=1.5, id = 'mode_weapon', 14 14 img='starlit-ui-icon-weapon.png', close=true, color = cmode'weapon'}; 15 15 {kind = 'contact', w=1.5,h=1.5, id = 'mode_psi', 16 16 img='starlit-ui-icon-psi.png', close=true, color = cmode'psi'}; 17 17 }; 18 18 {kind = 'hztl'; 19 - {kind = 'contact', w=1.5,h=1.5, id = 'open_elements', 19 + {kind = 'contact', w=1.5,h=1.5, id = 'open_nano', 20 20 img='starlit-ui-icon-element.png'}; 21 21 {kind = 'contact', w=1.5,h=1.5, id = 'open_suit', 22 22 img='starlit-item-suit.png^[hsl:200:-.7:0'}; 23 23 {kind = 'contact', w=1.5,h=1.5, id = 'open_psi', 24 24 img='starlit-ui-icon-psi-cfg.png'}; 25 25 {kind = 'contact', w=1.5,h=1.5, id = 'open_body', 26 26 img='starlit-ui-icon-self.png'}; ................................................................................ 49 49 else 50 50 setSuitMode(e) 51 51 end 52 52 return true 53 53 end 54 54 end 55 55 56 - if fields.open_elements then 57 - user:openUI('starlit:user-menu', 'compiler') 56 + if fields.open_nano then 57 + user:openUI('starlit:user-menu', 'nano') 58 58 return true 59 59 elseif fields.open_psi then 60 60 user:openUI('starlit:user-menu', 'psi') 61 61 return true 62 62 elseif fields.open_suit then 63 63 if not user:naked() then 64 64 user:openUI('starlit:user-menu', 'suit') ................................................................................ 118 118 end 119 119 120 120 local function abilityMenu(a) 121 121 -- select primary/secondary abilities or activate ritual abilities 122 122 local p = {kind = 'vert'} 123 123 for _, o in ipairs(a.order) do 124 124 local m = a.menu[o] 125 - table.insert(p, {kind='hbar', fac=0.5, text=string.format("<b>%s</b>",m.label), w=a.w, h = .5}) 125 + table.insert(p, {kind='hbar', fac=0, text=string.format("<b>%s</b>",m.label), w=a.w, h = .5}) 126 126 table.insert(p, wrapMenu(a.w, a.h, 1.2, 2, m.opts)) 127 127 end 128 128 return p 129 129 end 130 130 131 131 local function pptrMatch(a,b) 132 132 if a == nil or b == nil then return false end ................................................................................ 133 133 return (a.chipID ~= nil and (a.chipID == b.chipID and a.pgmIndex == b.pgmIndex)) 134 134 or (a.ref ~= nil and a.ref == b.ref) 135 135 end 136 136 137 137 starlit.interface.install(starlit.type.ui { 138 138 id = 'starlit:user-menu'; 139 139 pages = { 140 - compiler = { 140 + nano = { 141 141 setupState = function(state, user) 142 142 -- nanotech/suit software menu 143 143 local chips = user.entity:get_inventory():get_list 'starlit_suit_chips' -- FIXME need better subinv api 144 144 local sw = starlit.mod.electronics.chip.usableSoftware(chips) 145 145 state.suitSW = {} 146 146 local dedup = {} 147 147 for i, r in ipairs(sw) do if ................................................................................ 168 168 end 169 169 end 170 170 if not pgm then return false end -- HAX 171 171 172 172 -- kind=active programs must be assigned to a command slot 173 173 -- kind=direct programs must open their UI 174 174 -- kind=passive programs must toggle on and off 175 + local inv = user.entity:get_inventory() 175 176 local function suitCtx(pgm) 176 - local chips = user.entity:get_inventory():get_list 'starlit_suit_chips' 177 - local pgmctx = starlit.mod.electronics.chip.usableSoftware(chips, {pgm})[1] 177 + local uuid = starlit.mod.electronics.chip.read(pgm.chip).uuid 178 178 return { 179 179 context = 'suit'; 180 - program = pgmctx; 180 + program = pgm; 181 + verify = function() -- ew!! 182 + local chipInSlot = inv:get_stack('starlit_suit_chips', pgm.chipSlot) 183 + local csd = starlit.mod.electronics.chip.read(chipInSlot) 184 + return csd.uuid == uuid 185 + end; 186 + saveConf = function(cfg) cfg = cfg or pgm.file.body.conf 187 + pgm.file.body.conf = cfg 188 + pgm.fd:write(pgm.file) 189 + inv:set_stack('starlit_suit_chips', pgm.chipSlot, pgm.fd.chip) 190 + user:reconfigureSuit() 191 + end; 192 + pullConf = function() 193 + local stack = inv:get_stack('starlit_suit_chips', pgm.chipSlot) 194 + pgm.fd.chip=stack 195 + pgm.file = pgm.fd:read() 196 + end; 181 197 } 182 198 end 183 199 184 200 if pgm.sw.powerKind == 'active' then 185 201 if cfg then 186 202 user:openUI(pgm.sw.ui, 'index', { 187 203 context = 'suit'; ................................................................................ 495 511 if q.powerMode_off then suitMode = 'off' 496 512 elseif q.powerMode_save then suitMode = 'powerSave' 497 513 elseif q.powerMode_on then suitMode = 'on' end 498 514 if suitMode then 499 515 user:suitPowerStateSet(suitMode) 500 516 return true 501 517 end 502 - end; 503 - }; 504 - }; 505 -}) 506 - 507 -local function compilerCanPrint(user, cpl, scm) 508 - local output = ItemStack(scm.sw.output):get_definition() 509 - local fab = output._starlit.fab 510 - local sw = scm.sw 511 - local ok, consume, unsat, leftover, itemSpec = fab:seek { 512 - user.entity:get_inventory():get_list 'main'; 513 - } 514 - 515 - local cost = { 516 - consume = consume, unsat = unsat, leftover = leftover, itemSpec = itemSpec; 517 - runtimeEstimate = scm.speed + cpl.speed + (fab.time and fab.time.print or 0); 518 - power = cpl.powerCost + scm.powerCost; 519 - ram = (cpl.cost and cpl.cost.ram or 0) 520 - + (scm.cost and scm.cost.ram or 0); 521 - cycles = (cpl.cost and cpl.cost.cycles or 0) 522 - + (scm.cost and scm.cost.cycles or 0); 523 - } 524 - 525 - local userComp = starlit.mod.electronics.chip.sumCompute( 526 - user.entity:get_inventory():get_list 'starlit_suit_chips' 527 - ) 528 - 529 - if ok and cost.power <= user:suitCharge() and cost.ram <= userComp.ram then 530 - return true, cost 531 - else return false, cost end 532 -end 533 - 534 --- TODO destroy suit interfaces when power runs out or suit/chip is otherwise disabled 535 -starlit.interface.install(starlit.type.ui { 536 - id = 'starlit:compile-matter-component'; 537 - sub = { 538 - suit = function(state, user, evt) 539 - if evt.kind == 'disrobe' then state:close() 540 - elseif evt.kind == 'power' and evt.mode == 'off' then state:close() end 541 - end; 542 - playerInventory = function(state,user) 543 - -- refresh 544 - end; 545 - }; 546 - pages = { 547 - index = { 548 - setupState = function(state, user, ctx) 549 - state.pgm = ctx.program 550 - state.select = {} 551 - local E = starlit.mod.electronics 552 - if ctx.context == 'suit' then 553 - state.fetch = function() 554 - local cst = user.entity:get_inventory():get_list 'starlit_suit_chips' 555 - local cl = {order={}, map={}, slot={}} 556 - for i, c in ipairs(cst) do 557 - if not c:is_empty() then 558 - local d = E.chip.read(c) 559 - local co = { 560 - stack = c; 561 - data = d; 562 - } 563 - table.insert(cl.order, co) 564 - cl.map[d.uuid] = co 565 - cl.slot[i] = co 566 - end 567 - end 568 - 569 - -- kill me fam 570 - if ( state.select.chip 571 - and state.select.chip ~= true 572 - and not cl.map[state.select.chip]) 573 - or (state.select.scm 574 - and not state.select.scms[state.select.scm]) 575 - then 576 - -- chip or pgm no longer available 577 - user:suitSound 'starlit-error' 578 - state.select = {} 579 - end 580 - state.select.chips = cl 581 - 582 - state.select.scms = {} 583 - if state.select.chip then 584 - state.select.scms = E.chip.usableSoftware(cst,nil, function(s) 585 - if state.select.chip ~= true then 586 - if cl.slot[s.chipSlot].data.uuid ~= state.select.chip then 587 - return false 588 - end 589 - end 590 - return s.sw.kind == 'schematic' 591 - end) 592 - end 593 - 594 - end 595 - end 596 - end; 597 - 598 - onClose = function(state, user) 599 - user:suitSound 'starlit-quit' 600 - end; 601 - handle = function(state, user, q) 602 - local sel = state.select 603 - state.fetch() 604 - local chips = state.select.chips 605 - local function chirp() 606 - user:suitSound 'starlit-nav' 607 - end 608 - 609 - local function trySelection(id) 610 - if sel[id] == nil then 611 - for k in next, q do 612 - local pat = "^"..id.."_(%d+)$" -- ew 613 - local idx = k:match(pat) 614 - if idx then 615 - local cm = tonumber(idx) 616 - if cm then 617 - chirp() 618 - sel[id] = cm 619 - return true 620 - end 621 - end 622 - end 623 - end 624 - end 625 - 626 - if sel.chip == nil then 627 - if q.showAll then 628 - chirp() 629 - sel.chip = true 630 - return true 631 - elseif q.find then 632 - chirp() 633 - -- TODO 634 - return true 635 - end 636 - end 637 - 638 - if trySelection('chip') then 639 - return true 640 - elseif trySelection('scm') then 641 - return true 642 - else 643 - if q.back then 644 - chirp() 645 - if sel.input then 646 - sel.input = nil 647 - elseif sel.scm then 648 - sel.scm = nil 649 - elseif sel.chip then 650 - sel.chip = nil 651 - end 652 - return true 653 - elseif q.commit then 654 - if not sel.input then 655 - chirp() 656 - sel.input = true 657 - return true 658 - else 659 - local scm = sel.scms[sel.scm] 660 - local ok, cost = compilerCanPrint(user, state.pgm, scm) 661 - if ok then 662 - user:suitSound 'starlit-configure' 663 - -- consume consumables 664 - -- add print job 665 - state.select = {} 666 - return true 667 - else 668 - user:suitSound 'starlit-error' 669 - end 670 - end 671 - end 672 - end 673 - 674 - end; 675 - 676 - render = function(state, user) 677 - local sel, pgmSelector = state.select, {} 678 - state.fetch() 679 - 680 - local function pushSelector(id, item, label, desc, req) 681 - local rh = .5 682 - local label = {kind = 'text', w = 10-1.5, h=1.5; 683 - text = '<global valign=middle>'..lib.str.htsan(label) } 684 - if req then 685 - label.h = label.h - rh - .2 686 - 687 - local imgs = {} 688 - for ci,c in ipairs(req) do 689 - for ei, e in ipairs(c.list) do 690 - table.insert(imgs, {kind = 'img', w=rh, h=rh, img=e.img}) 691 - end 692 - end 693 - label = {kind = 'vert', w = 10-1.5, h=1.5; 694 - label; 695 - {kind ='hztl', w=10-1.5, h=rh; unpack(imgs); } 696 - } 697 - end 698 - table.insert(pgmSelector, {kind = 'hztl', w=10,h=1.5; 699 - {kind = 'contact', id=id, w=1.5, h=1.5; 700 - item = item; 701 - color = {hue=220, sat=0, lum=0}; 702 - desc = desc; 703 - }; 704 - label; 705 - }) 706 - end 707 - 708 - local back = {kind = 'button', id='back', label = '<- Back', w=10,h=1.2} 709 - if sel.chips == nil then 710 - table.insert(pgmSelector, {kind = 'img', img = 'starlit-ui-alert.png', w=2, h=2}) 711 - elseif sel.chip == nil then 712 - for i, c in ipairs(sel.chips.order) do 713 - -- TODO filter out chips without schematics? 714 - pushSelector('chip_' .. c.data.uuid, c.stack, c.data.label) 715 - end 716 - if next(sel.chips.order) then 717 - table.insert(pgmSelector, {kind = 'hztl', w=10,h=1.5; 718 - {kind = 'button', w=5,h=1.5; id='showAll', label='Show All'}; 719 - {kind = 'button', w=5,h=1.5; id='find', label='Find'}; 720 - }) 721 - end 722 - else 723 - if sel.scm == nil then 724 - for idx, ent in ipairs(sel.scms) do 725 - local fab = ItemStack(ent.sw.output):get_definition()._starlit.fab 726 - if fab.flag.print then 727 - local req = fab:visualize() 728 - pushSelector('scm_' .. idx, ent.sw.output, ent.sw.name, nil, req) 729 - end 730 - end 731 - table.insert(pgmSelector, back) 732 - else 733 - local scm = sel.scms[sel.scm] 734 - local output = ItemStack(scm.sw.output):get_definition() 735 - local fab = output._starlit.fab 736 - local sw = scm.sw 737 - local function unmet(str) 738 - return lib.color(1,.3,.3):fmt(str) 739 - end 740 - table.insert(pgmSelector, {kind = 'hztl', w=10, h=1.2; 741 - {kind = 'img', item = sw.output, w=1.2, h=1.2, desc=output.description}; 742 - {kind = 'text', text = string.format('<global valign=middle><b>%s</b>', lib.str.htsan(sw.name)), w=10-1.2,h=1.2}; 743 - }) 744 - local inputTbl = {kind = 'vert', w=5,h=0; 745 - {kind = 'hbar', w=5, h=.5, text=sel.input and 'Input Plan' or 'Input'}}; 746 - local costTbl = {kind = 'vert', w=5,h=0; 747 - {kind = 'hbar', w=5, h=.5, text=sel.input and 'Process Plan' or 'Process'}}; 748 - local reqPane = {kind = 'pane', id='reqPane', w=10, h=7; 749 - {kind = 'hztl', w=10,h=0; inputTbl, costTbl} 750 - } 751 - local function pushCost(x, t, val) 752 - table.insert(costTbl, {kind='label', w=4.5,h=.5,x=x; 753 - text=string.format('%s: %s',t,val); 754 - }) 755 - end 756 - local function pushComputeCosts(header, p) 757 - if p then 758 - table.insert(costTbl, {kind = 'label', w=5, h=.5, x=0; text=header}); 759 - if p.cycles then 760 - pushCost(.5, 'Compute', lib.math.siUI({'cycle','cycles'}, p.cycles, true)) 761 - end 762 - if p.power then 763 - local str = lib.math.siUI('J', p.power) 764 - if p.power > user:suitCharge() then str = unmet(str) end 765 - pushCost(.5, 'Power', str) 766 - end 767 - if p.ram then 768 - local str = string.format("%s / %s", 769 - lib.math.siUI('B', p.ram), 770 - lib.math.siUI('B', state.pgm.comp.ram)) 771 - if p.ram > state.pgm.comp.ram then str = unmet(str) end 772 - pushCost(.5, 'Memory', str) 773 - end 774 - end 775 - end 776 - 777 - local function fabToUI(x, inputTbl, req) 778 - for ci,c in ipairs(req) do 779 - table.insert(inputTbl, {kind = 'label', w=5-x, h=.5, x=x; 780 - text=lib.str.capitalize(c.header)}); 781 - for ei,e in ipairs(c.list) do 782 - table.insert(inputTbl, {kind = 'hztl', w=4.5-x, h=.5, x=x+.5; 783 - {kind='img', w=.5,h=.5, img=e.img}; 784 - {kind='label', w=3.3,h=.5,x=.2, text=lib.str.capitalize(e.label)}; 785 - }); 786 - end 787 - end 788 - end 789 - 790 - local commitHue=120, commitLabel 791 - if not sel.input then 792 - commitLabel = 'Plan' 793 - fabToUI(0, inputTbl, fab:visualize()) 794 - local function pushComputeCostsSw(header, p) 795 - if p.sw.cost then 796 - pushComputeCosts(header, { 797 - cycles = p.sw.cost.cycles; 798 - power = p.powerCost; 799 - ram = p.sw.cost.ram; 800 - }) 801 - end 802 - end 803 - pushComputeCostsSw('Schematic', scm) 804 - pushComputeCostsSw('Compiler', state.pgm) 805 - else 806 - commitLabel = 'Commit' 807 - pushComputeCosts('Total', { 808 - cycles = (scm.sw.cost and scm.sw.cost.cycles or 0) 809 - + (state.pgm.sw.cost and state.pgm.sw.cost.cycles or 0); 810 - power = (scm.powerCost or 0) 811 - + (state.pgm.powerCost or 0) 812 - + (fab.cost and fab.cost.power or 0); 813 - ram = (scm.sw.cost and scm.sw.cost.ram or 0) 814 - + (state.pgm.sw.cost and state.pgm.sw.cost.ram or 0); 815 - }) 816 - if fab.time and fab.time.print then 817 - pushCost(0, 'Job Runtime', lib.math.timespec(fab.time.print + scm.speed)) 818 - pushCost(.5, 'Print Time', lib.math.timespec(fab.time.print)) 819 - pushCost(.5, 'CPU Time', lib.math.timespec(scm.speed + state.pgm.speed)) 820 - end 821 - local ok, compileCost = compilerCanPrint(user, state.pgm, scm) 822 - fabToUI(0, inputTbl, compileCost.itemSpec:visualize()) 823 - 824 - if next(compileCost.unsat) then 825 - local vis = compileCost.unsat:visualize() 826 - for si, s in ipairs(vis) do 827 - s.header = 'Missing ' .. s.header 828 - for ei, e in ipairs(s.list) do 829 - e.label = lib.color(1,.2,.2):fmt(e.label) 830 - end 831 - end 832 - fabToUI(0, inputTbl, vis) 833 - end 834 - if not ok then commitHue = 0 end 835 - end 836 - table.insert(pgmSelector, reqPane) 837 - table.insert(pgmSelector, {kind = 'hztl', w=10,h=1.2; 838 - {kind = 'button', id='back', label = '← Back', w=5,h=1.2}; 839 - {kind = 'button', id='commit', label = commitLabel .. ' →', w=5,h=1.2, color={hue=commitHue,sat=0,lum=0}}; 840 - }) 841 - end 842 - end 843 - 844 - return starlit.ui.build { 845 - kind = 'hztl', padding = 0.5; w = 20, h = 10, mode = 'sw'; 846 - {kind = 'vert', w = 5, h = 5; 847 - {kind = 'hbar', fac=0, w = 5, h = .5, text = '<b><left>Recent Prints</left></b>'}; 848 - }; 849 - {kind = 'vert', w = 10, h = 10; 850 - {kind = 'hbar', fac=0, w = 10, h = .5, text = '<b>Program Select</b>'}; 851 - {kind = 'pane', w = 10, h = 9.5, id='pgmSelect'; 852 - unpack(pgmSelector) 853 - }; 854 - }; 855 - {kind = 'vert', w = 5, h = 10; 856 - {kind = 'hbar', fac=0, w = 5, h = .5, text = '<b><right>Print Queue</right></b>'}; 857 - }; 858 - } 859 518 end; 860 519 }; 861 520 }; 862 521 })
Modified mods/starlit/store.lua from [9cc49bcaa7] to [ac25f2dec5].
20 20 for k,v in pairs(starlit.world.stats) do 21 21 statStructFields[k] = v.srzType or ( 22 22 (v.base == true or v.base > 0) and T.s16 or T.u16 23 23 ) 24 24 end 25 25 26 26 starlit.store.compilerJob = G.struct { 27 - schematic = T.str; 28 - progress = T.clamp; 27 + schematic = T.str; 28 + cyclesLeft = T.u64; 29 + timeLeft = T.decimal; 29 30 } 30 31 31 32 starlit.store.persona = G.struct { 32 33 name = T.str; 33 34 species = T.str; 34 35 speciesVariant = T.str; 35 36 background = T.str;
Modified mods/starlit/suit.lua from [8324bad06e] to [f9e736d40a].
427 427 break 428 428 end 429 429 end 430 430 local fn if s.powerKind == 'passive' 431 431 then fn = s.run 432 432 else fn = s.bgProc 433 433 end 434 - function prop.saveConf(cfg) cfg = cfg or conf 434 + function prop.saveConf(cfg) cfg = cfg or prop.file 435 435 prop.fd:write(cfg) 436 436 inv:set_stack('starlit_suit_chips', prop.chipSlot, prop.fd.chip) 437 437 reconfSuit = true 438 438 end 439 + function prop.pullConf() 440 + local stack = inv:get_stack('starlit_suit_chips', suitprog.chipSlot) 441 + prop.fd.chip=stack 442 + prop.file = prop.fd:read() 443 + end 439 444 function prop.giveItem(st) 440 445 u:thrustUpon(st) 441 446 end 442 447 443 448 if enabled and fn(u, prop, suitInterval, runState) then 444 449 runState.pgmsRun[s] = true 445 450 end
Modified mods/starlit/terrain.lua from [4e1556f916] to [e1d816e7a5].
240 240 tiles = {'starlit-terrain-feldspar.png'}; 241 241 excludeOre = true; 242 242 recover = starlit.type.fab { 243 243 time = { shred = 3; }; 244 244 cost = { shredPower = 3; }; 245 245 }; 246 246 recover_vary = function(rng, ctx) 247 - -- print('vary!', rng:int(), rng:int(0,10)) 248 247 return starlit.type.fab { 249 248 element = { 250 249 aluminum = rng:int(0,4); 251 250 potassium = rng:int(0,2); 252 251 calcium = rng:int(0,2); 253 252 } 254 253 };
Modified mods/starlit/ui.lua from [08cb8bbbbd] to [16bf595c8c].
150 150 widget('container[%s,%s]%scontainer_end[]', state.x, state.y, src) 151 151 -- TODO alignments 152 152 state.x=state.x + state.spacing + st.w 153 153 state.h = math.max(state.h, st.h) 154 154 end 155 155 state.h = state.h + state.padding 156 156 state.w = state.x + state.padding/2 157 + elseif def.kind == 'hwrap' then 158 + local idx, rowH, totalH = 0,0,0 159 + local cols = def.cols or math.huge 160 + local startX = state.x 161 + local maxX = startX 162 + for _, w in ipairs(def) do idx = idx + 1 163 + local src, st = starlit.ui.build(w, state) 164 + -- TODO alignments 165 + rowH = math.max(rowH, st.h) 166 + if idx > cols or def.w and (state.x + state.spacing + st.w > def.w) then 167 + totalH = totalH + rowH 168 + state.x = startX 169 + rowH,idx = 0,0 170 + state.y = state.y + state.spacing + st.h 171 + end 172 + widget('container[%s,%s]%scontainer_end[]', state.x, state.y, src) 173 + state.x=state.x + state.spacing + st.w 174 + maxX = math.max(state.x, maxX) 175 + end 176 + totalH = totalH + rowH 177 + state.h = math.max(state.h, totalH) + state.padding 178 + state.w = state.x + state.padding/2 179 + state.x = maxX 157 180 elseif def.kind == 'pane' then 158 181 widget('scroll_container[%s,%s;%s,%s;%s;vertical]', 159 182 state.x, state.y, state.w, state.h, 160 183 def.id) 161 184 local y = 0 162 185 for _, w in ipairs(def) do 163 186 local src, st = starlit.ui.build(w, state)
Modified mods/starlit/user.lua from [c928629a64] to [aa3a95c242].
1010 1010 local ul = self.hud.led.map[kind] 1011 1011 if ul then 1012 1012 if time - ul.origin > minFreq then 1013 1013 ul.origin = time 1014 1014 else return end 1015 1015 end 1016 1016 1017 - if urgency > 0 then 1017 + if urgency ~= 0 then 1018 1018 local urgencies = { 1019 + [-2] = {sound = 'starlit-success'}; 1020 + [-1] = {sound = 'starlit-nav'}; 1019 1021 [1] = {sound = 'starlit-alarm'}; 1020 1022 [2] = {sound = 'starlit-alarm-urgent'}; 1021 1023 } 1022 1024 local urg = urgencies[urgency] or urgencies[#urgencies] 1023 1025 1024 1026 if time - self.cooldownTimes.alarm > 1.5 then 1025 1027 self.cooldownTimes.alarm = time ................................................................................ 1085 1087 return true; -- TODO 1086 1088 end; 1087 1089 1088 1090 --------------- 1089 1091 -- inventory -- 1090 1092 --------------- 1091 1093 give = function(self, item) 1094 + item = ItemStack(item) 1092 1095 local inv = self.entity:get_inventory() 1093 1096 local function is(grp) 1094 1097 return minetest.get_item_group(item:get_name(), grp) ~= 0 1095 1098 end 1096 1099 -- TODO notif popups 1097 1100 if is 'specialInventory' then 1098 1101 --[[ ................................................................................ 1130 1133 } 1131 1134 1132 1135 local clockInterval = 1.0 1133 1136 starlit.startJob('starlit:clock', clockInterval, function(delta) 1134 1137 for id, u in pairs(starlit.activeUsers) do 1135 1138 u.hud.elt.time:update() 1136 1139 u:updateLEDs() 1140 + local ui = starlit.activeUI[u.name] 1141 + if ui and (ui.self.refresh or ui.self.pages[ui.page].refresh) then 1142 + ui.self:show(u) 1143 + end 1137 1144 end 1138 1145 end) 1139 1146 1140 1147 -- performs a general HUD refresh, mainly to update the HUD backlight brightness 1141 1148 local hudInterval = 10 1142 1149 starlit.startJob('starlit:hud-refresh', hudInterval, function(delta) 1143 1150 for id, u in pairs(starlit.activeUsers) do
Modified mods/starlit/world.lua from [822a964373] to [d1f4916ac1].
115 115 attached_node = 3; 116 116 }; 117 117 drop = st.drop; 118 118 _starlit = { 119 119 plant = { 120 120 id = id, stage = n; 121 121 }; 122 - recover = starlit.type.fab { 122 + recover = b.recover or starlit.type.fab { 123 123 time = { shred = .3; }; 124 124 cost = { shredPower = 1; }; 125 125 }; 126 - recover_vary = function(rng, ctx) 126 + recover_vary = b.recover_vary or function(rng, ctx) 127 127 return starlit.type.fab { 128 128 element = { 129 - carbon = rng:int(0,1); 129 + carbon = rng:int(0,2); 130 130 potassium = rng:int(0,1); 131 + magnesium = rng:int(0,b.biolum and 2 or 1); 131 132 } 132 133 }; 133 134 end; 134 135 }; 135 136 } 136 137 if st.swap then 137 138 base.node_dig_prediction = ""
Modified mods/vtlib/math.lua from [2d47a7e2f1] to [557fe13815].
158 158 function fn.timespec(n) 159 159 if n == 0 then return '0s' end 160 160 if n < 0 then return '-' .. fn.timespec(n*-1) end 161 161 162 162 local sec = math.floor(n % 60) 163 163 local min = math.floor(n / 60) 164 164 local hr = math.floor(min / 60) 165 + min = min % 60 165 166 local spec = {} 166 167 167 168 if hr ~= 0 then table.insert(spec, string.format("%shr", hr)) end 168 169 if min ~= 0 then table.insert(spec, string.format("%sm", min)) end 169 170 if sec ~= 0 then table.insert(spec, string.format("%ss", sec)) end 170 171 return table.concat(spec, ' ') 171 172 end 172 173 return fn