Index: mods/starlit-electronics/init.lua ================================================================== --- mods/starlit-electronics/init.lua +++ mods/starlit-electronics/init.lua @@ -41,11 +41,11 @@ -- starlit.item.chip = lib.registry.mk 'starlit_electronics:chip' -- software is of one of the following types: -- schematic: program for your matter compiler that enables crafting a given item. --- output: the result +-- output (convertible to ItemStack): the result -- driver: inserted into a Core to control attached hardware -- suitPower: provides suit functionality like nanoshredding or healing -- passive powers are iterated on suit application/configuration and upon fst-tick -- cost: what the software needs to run. some fields are fab-specific -- energy: for fab, total energy cost of process in joules @@ -216,17 +216,17 @@ title = def.name; desc = def.desc; color = lib.color(0,.2,1); props = { { title = 'Optimal Capacity', affinity = 'info'; - desc = lib.math.si('J', def.capacity) }; + desc = lib.math.siUI('J', def.capacity) }; { title = 'Discharge Rate', affinity = 'info'; - desc = lib.math.si('W', def.dischargeRate) }; + desc = lib.math.siUI('W', def.dischargeRate) }; { title = 'Charge Efficiency', affinity = 'info'; desc = string.format('%s%%', (1-def.leak) * 100) }; { title = 'Size', affinity = 'info'; - desc = lib.math.si('m', def.fab.size.print) }; + desc = lib.math.siUI('m', def.fab.size.print) }; }; }; _starlit = { event = { create = function(st, how) @@ -276,20 +276,20 @@ local batteryTiers = { makeshift = { name = 'Makeshift'; capacity = .5, decay = 3, leak = 2, dischargeRate = 1, fab = starlit.type.fab { - metal = {copper=10}; + element = {copper=10}; }; desc = "Every attosecond this electrical abomination doesn't explode in your face is but the unearned grace of the Wild Gods."; complexity = 1; sw = {rarity = 1}; }; imperial = { name = 'Imperial'; capacity = 2, decay = 2, leak = 2, dischargeRate = 2; fab = starlit.type.fab { - metal = {copper=15, iron = 20}; + element = {copper=15, iron = 20}; size = { print = 0.1 }; }; desc = "The Empire's native technology is a lumbering titan: bulky, inefficient, unreliable, ugly, and awesomely powerful. Their batteries are no exception, with raw capacity and throughput that exceed even Usukinwya designs."; drm = 1; complexity = 2; @@ -296,21 +296,23 @@ sw = {rarity = 2}; }; commune = { name = 'Commune'; capacity = 1, decay = .5, leak = .2, dischargeRate = 1; fab = starlit.type.fab { - metal = {vanadium=50, steel=10}; + element = {vanadium = 50}; + metal = {steel=10}; size = { print = 0.05 }; }; desc = "The Commune's proprietary battery designs prioritize reliability, compactness, and maintenance concerns above raw throughput, with an elegance of engineering and design that would make a Su'ikuri cry."; complexity = 5; sw = {rarity = 3}; }; usukwinya = { name = 'Usukwinya'; capacity = 2, decay = 1, leak = 1, dischargeRate = 1.5, fab = starlit.type.fab { - metal = {vanadium=30, argon=10}; + element = {argon=10}; + metal = {vanadium=30}; size = { print = 0.07 }; }; desc = "A race of consummate value engineers, the Usukwinya have spent thousands of years refining their tech to be as cheap to build as possible, without compromising much on quality. The Tradebirds drive an infamously hard bargain, but their batteries are more than worth their meagre cost."; drm = 2; sw = {rarity = 10}; @@ -317,21 +319,23 @@ complexity = 15; }; eluthrai = { name = 'Eluthrai'; capacity = 3, decay = .4, leak = .1, dischargeRate = 1.5, fab = starlit.type.fab { - metal = {beryllium=20, platinum=20, technetium = 1, cinderstone = 10 }; + element = {beryllium=20, platinum=20, technetium = 1}; + metal = {cinderstone = 10}; size = { print = 0.03 }; }; desc = "The uncompromising Eluthrai are never satisfied until every quantifiable characteristic of their tech is maximally optimised down to the picoscale. Their batteries are some of the best in the Reach, and unquestionably the most expensive -- especially for those lesser races trying to copy the designs without the benefit of the sublime autofabricator ecosystem of the Eluthrai themselves."; complexity = 200; sw = {rarity = 0}; -- you think you're gonna buy eluthran schematics on SuperDiscountNanoWare.space?? }; firstborn = { name = 'Firstborn'; capacity = 5, decay = 0.1, leak = 0, dischargeRate = 3; fab = starlit.type.fab { - metal = {neodymium=20, xenon=150, technetium=5, sunsteel = 10 }; + element = {neodymium=20, xenon=150, technetium=5}; + metal = {sunsteel = 10}; crystal = {astrite = 1}; size = { print = 0.05 }; }; desc = "Firstborn engineering seamlessly merges psionic effects with a mastery of the physical universe unattained by even the greatest of the living Starsouls. Their batteries reach levels of performance that strongly imply Quantum Gravity Theory -- and several major holy books -- need to be rewritten. From the ground up."; complexity = 1000; @@ -369,12 +373,11 @@ }; chemical = { name = 'Chemical'; desc = ''; fab = starlit.type.fab { - element = { lithium = 3}; - metal = {iron = 5}; + element = { lithium = 3 }; size = {print=1.0}; }; sw = { cost = { cycles = 1e9; -- 1 bil cycles @@ -411,14 +414,12 @@ name = 'Hybrid'; desc = ''; capacity = 1; fab = starlit.type.fab { element = { - lithium = 3; - }; - metal = { - iron = 5; + lithium = 10; + carbon = 20; }; size = {print=1.5}; }; sw = { cost = { @@ -502,10 +503,11 @@ end starlit.item.sw.link(swID, { kind = 'schematic'; name = name .. ' Schematic'; + input = fab; output = id; size = bType.sw.pgmSize; cost = bType.sw.cost; rarity = rare; }) @@ -688,19 +690,19 @@ end def = assert(def._starlit.chip) end local props = { {title = 'Clock Rate', affinity = 'info'; - desc = lib.math.si('Hz', def.clockRate)}; + desc = lib.math.siUI('Hz', def.clockRate)}; {title = 'RAM', affinity = 'info'; - desc = lib.math.si('B', def.ram)}; + desc = lib.math.siUI('B', def.ram)}; } if not defOnly then table.insert(props, { title = 'Free Storage', affinity = 'info'; - desc = lib.math.si('B', E.chip.freeSpace(ch, data)) .. ' / ' - .. lib.math.si('B', def.flash); + desc = lib.math.siUI('B', E.chip.freeSpace(ch, data)) .. ' / ' + .. lib.math.siUI('B', def.flash); }) local swAffMap = { schematic = 'schematic'; suitPower = 'ability'; driver = 'driver'; @@ -732,11 +734,11 @@ }) end else table.insert(props, { title = 'Flash Storage', affinity = 'info'; - desc = lib.math.si('B', def.flash); + desc = lib.math.siUI('B', def.flash); }) end return starlit.ui.tooltip { title = data.label and data.label~='' and string.format('<%s>', data.label) or def.name; color = lib.color(.6,.6,.6); @@ -784,11 +786,11 @@ name = t.name; clockRate = t.clockRate; flash = t.flash; ram = t.ram; powerEfficiency = t.powerEfficiency; -- cycles per joule - fab = { + fab = starlit.type.fab { flag = { silicompile = true; }; time = { silicompile = t.size * 24*60; @@ -868,11 +870,12 @@ return E.chip.fileOpen(self.chip, self.inode, fn) end; }; } -function E.chip.usableSoftware(chips,pgm) +function E.chip.usableSoftware(chips,pgm,pred) + pred = pred or function() return true end local comp = E.chip.sumCompute(chips) local r = {} local unusable = {} local sw if pgm then if type(pgm) == 'string' then @@ -897,11 +900,11 @@ end end end for _, s in pairs(sw) do - if s.sw.cost.ram <= comp.ram then + if s.sw.cost.ram <= comp.ram and pred(s) then table.insert(r, { sw = s.sw; chip = s.chip, chipSlot = s.chipSlot; file = s.file; fd = E.chip.fileHandle(s.chip, s.inode); Index: mods/starlit-electronics/mod.conf ================================================================== --- mods/starlit-electronics/mod.conf +++ mods/starlit-electronics/mod.conf @@ -1,4 +1,4 @@ name = starlit_electronics title = starlit electronics description = basic electronic components and logic -depends = starlit +depends = starlit, starlit_material Index: mods/starlit-electronics/sw.lua ================================================================== --- mods/starlit-electronics/sw.lua +++ mods/starlit-electronics/sw.lua @@ -101,10 +101,11 @@ user.action.prog.shred = user.action.prog.shred + ctx.how.delta or 0 end --print('shred progress: ', user.action.prog.shred) if user.action.prog.shred >= shredTime then minetest.remove_node(what) + minetest.check_for_falling(what) --print('shred complete') user:suitSound 'starlit-success' if fab then local vf = fab if vary then Index: mods/starlit-material/elements.lua ================================================================== --- mods/starlit-material/elements.lua +++ mods/starlit-material/elements.lua @@ -25,10 +25,15 @@ silicon = { name = 'silicon', sym = 'Si', n = 14, density = 2.329; metal = true; -- can be forged into an ingot color = lib.color(.6,.6,.4); }; + neodymium = { + name = 'neodymium', sym = 'Nd', n= 60, density = 7.01; + metal = true; + color = lib.color(1,1,1); + }; potassium = { name = 'potassium', sym = 'K', n = 19, density = 0.862; -- potassium is technically a metal but it's so soft -- it can be easily nanoworked without high temps, so -- ingots make no sense Index: mods/starlit-material/init.lua ================================================================== --- mods/starlit-material/init.lua +++ mods/starlit-material/init.lua @@ -20,6 +20,7 @@ starlit.mod.material = M starlit.include 'elements' starlit.include 'liquids' +starlit.include 'metals' ADDED mods/starlit-material/liquids.lua Index: mods/starlit-material/liquids.lua ================================================================== --- mods/starlit-material/liquids.lua +++ mods/starlit-material/liquids.lua @@ -0,0 +1,14 @@ +local lib = starlit.mod.lib +local M = starlit.mod.material + +starlit.world.material.liquid.meld { + water = { + name = 'water'; + composition = starlit.type.fab { + element = {hydrogen = 2.0, oxygen = 1.0}; + }; + density = 1.0; + desc = "the sine qua non of biological life"; + color = lib.color(.1,.2,1); + }; +} ADDED mods/starlit-material/metals.lua Index: mods/starlit-material/metals.lua ================================================================== --- mods/starlit-material/metals.lua +++ mods/starlit-material/metals.lua @@ -0,0 +1,14 @@ +local lib = starlit.mod.lib +local M = starlit.mod.material + +starlit.world.material.metal.meld { + steel = { + name = 'steel'; + composition = starlit.type.fab { + element = {iron = 2.0, carbon = 1.0}; + }; + density = 1.0; + desc = "steel is a widely used alloy of iron and carbon"; + color = lib.color(.4,.4,.4); + }; +} Index: mods/starlit/element.lua ================================================================== --- mods/starlit/element.lua +++ mods/starlit/element.lua @@ -164,11 +164,11 @@ material = { kind = 'metal'; metal = id; }; fab = starlit.type.fab { - flag = {smelt= true}; + flag = {smelt=true}; element = comp(1e3); }; }; }); Index: mods/starlit/fab.lua ================================================================== --- mods/starlit/fab.lua +++ mods/starlit/fab.lua @@ -10,11 +10,11 @@ -- fabspecs. -- -- * used for determining quantities. that is, -- f*x = spec to make x instances of f -- --- new fab fields must be defined in starlit.type.fab.opClass. +-- new fab fields must be defined in starlit.type.fab.fields. -- this maps a name to fn(a,b,n) -> quant, where a is the first -- argument, b is a compounding amount, and n is a quantity of -- items to produce. fields that are unnamed will be underwritten local function fQuant(a,b,n) return ((a or 0)+(b or 0))*n end @@ -28,72 +28,93 @@ return f*n end local function fReq (a,b,n) return a or b end local function fFlag (a,b,n) return a and b end local function fSize (a,b,n) return math.max(a,b) end -local opClass = { + +local F = string.format +local lib = starlit.mod.lib + +local fields = { -- fabrication eligibility will be determined by which kinds -- of input a particular fabricator can introduce. e.g. a -- printer with a but no cache can only print items whose -- recipe only names elements as ingredients - - -- ingredients - element = fQuant; -- (g) - gas = fQuant; -- () - liquid = fQuant; -- (l) - crystal = fQuant; -- (g) - item = fQuant; -- n - metal = fQuant; -- (g) - metalIngot = fQuant; -- (g) + element = { + name = {"element", "elements"}; + string = function(x, n, long) + local el = starlit.world.material.element.db[x] + return lib.math.si('g', n) .. ' ' .. ((not long and el.sym) or el.name) + end; + image = function(x, n) + return string.format('starlit-element-%s.png', x) + end; + op = fQuant; + }; + metal ={ + name = {"metal", "metals"}; + string = function(x, n) + local met = starlit.world.material.metal.db[x] + return lib.math.si('g', n) .. ' ' .. met.name + end; + image = function(x, n) + local met = starlit.world.material.metal.db[x] + return ItemStack(met.form.ingot):get_definition().inventory_image + end; + op = fQuant; + }; + liquid = { + name = {"liquid", "liquids"}; + string = function(x, n) + local liq = starlit.world.material.liquid.db[x] + return lib.math.si('L', n) .. ' ' .. liq.name + end; + op = fQuant; + }; + gas = { + name = {"gas", "gasses"}; + string = function(x, n) + local gas = starlit.world.material.gas.db[x] + return lib.math.si('g', n) .. ' ' .. gas.name + end; + op = fQuant; + }; +-- crystal = { +-- op = fQuant; +-- }; + item = { + name = {"item", "items"}; + string = function(x, n) + local i = minetest.registered_items[x] + return tostring(n) .. 'x ' .. i.short_description + end; + }; + -- factors - cost = fFac; -- units vary - time = fFac; -- (s) + + cost = {op=fFac}; -- units vary + time = {op=fFac}; -- (s) -- print: base printing time - size = fSize; + size = {op=fSize}; -- printBay: size of the printer bay necessary to produce the item - req = fReq; - flag = fFlag; -- means that can be used to produce the item & misc flags + req = {op=fReq}; + flag = {op=fFlag}; -- means that can be used to produce the item & misc flags -- print: allow production with a printer -- smelt: allow production with a smelter -- all else defaults to underwrite } -local F = string.format -local strClass = { - element = function(x, n) - local el = starlit.world.material.element[x] - return lib.math.si('g', n) .. ' ' .. (el.sym or el.name) - end; - metal = function(x, n) - local met = starlit.world.material.metal[x] - return lib.math.si('g', n) .. ' ' .. met.name - end; - liquid = function(x, n) - local liq = starlit.world.material.liquid[x] - return lib.math.si('L', n) .. ' ' .. liq.name - end; - gas = function(x, n) - local gas = starlit.world.material.gas[x] - return lib.math.si('g', n) .. ' ' .. gas.name - end; - item = function(x, n) - local i = minetest.registered_items[x] - return tostring(n) .. 'x ' .. i.short_description - end; -} - local order = { 'element', 'metal', 'liquid', 'gas', 'item' } local lib = starlit.mod.lib local fab fab = lib.class { __name = 'starlit:fab'; - opClass = opClass; - strClass = strClass; + fields = fields; order = order; construct = function(q) return q end; __index = { elementalize = function(self) local e = fab {element = self.element or {}} @@ -156,26 +177,54 @@ if f then table.insert(fml, f) end fml = table.concat(fml, ' + ') return fml, ts end; + + visualize = function(self) + local all = {} + for i,o in ipairs(order) do + local t = {} + if self[o] then + for mat,amt in pairs(self[o]) do + local v = {} + v.id = mat + v.n = amt + if fields[o].string then + v.label = fields[o].string(mat,amt,true) + end + if fields[o].image then + v.img = fields[o].image(mat,amt) + end + table.insert(t,v) + end + end + if fields[o].sort then + table.sort(t, function(a,b) return fields[o].sort(a.id, b.id) end) + end + if next(t) then table.insert(all, { + id=o, list=t; + header=fields[o].name[t[2] and 2 or 1]; + }) end + end + return all + end; }; __tostring = function(self) local t = {} for i,o in ipairs(order) do - if self[o] then + if self[o] and fields[o].string then for mat,amt in pairs(self[o]) do if amt > 0 then - table.insert(t, strClass[o](mat, amt)) + table.insert(t, fields[o].string(mat, amt)) end end end end return table.concat(t, ", ") end; - __add = function(a,b) local new = fab {} for cat, vals in pairs(a) do new[cat] = lib.tbl.copy(vals) @@ -182,11 +231,11 @@ end for cat, vals in pairs(b) do if not new[cat] then new[cat] = lib.tbl.copy(vals) else - local f = opClass[cat] + local f = fields[cat].op for k,v in pairs(vals) do local n = f(new[cat][k], v, 1) new[cat][k] = n > 0 and n or nil end end @@ -196,11 +245,11 @@ __mul = function(x,n) local new = fab {} for cat, vals in pairs(x) do new[cat] = {} - local f = opClass[cat] + local f = fields[cat].op for k,v in pairs(vals) do local num = f(v,nil,n) new[cat][k] = num > 0 and num or nil end end ADDED mods/starlit/food.lua Index: mods/starlit/food.lua ================================================================== --- mods/starlit/food.lua +++ mods/starlit/food.lua @@ -0,0 +1,79 @@ +local F = starlit.item.food +local lib = starlit.mod.lib + +function F.impact(stack,f) + if stack and not f then f = stack:get_definition()._starlit.food end + local impact = f.impact and starlit.type.impact.clone(f.impact) or starlit.type.impact{} + + if impact.taste then + local aff = impact.taste > 0 and 'good' or 'bad' + table.insert(impact, {'taste', aff, {'morale', impact.taste}}) + end + + if stack then + impact = impact:effective(stack) + end + + return impact +end + +local function foodTip(stack, f) + local impact = F.impact(stack,f) + local props = impact:propTable() + + if f.mass then + table.insert(props, { + title='Mass', affinity='info'; + desc = lib.math.si('g', f.mass, nil, nil, 2); + }) + end + + return starlit.ui.tooltip { + title = f.name; + desc = f.desc; + props = props; + color = f.color; + }; +end + +F.foreach('starlit:gen-food', {}, function(id, f) + minetest.register_item(id, { + type = f.itemType or 'none'; + inventory_image = f.tex; + short_description = f.name; + description = foodTip(nil, f); + on_use = function(st, luser) + local user = starlit.activeUsers[luser:get_player_name()] + st:take_item(1) + local imp = F.impact(st,f) + imp:apply(user) + user:suitSound 'starlit-success' -- FIXME need proper eating sound + return st + end; + _starlit = { + food = f; + recover = f.recover; + mass = f.mass; + }; + }) +end) + +starlit.item.seed.foreach('starlit:gen-seed', {}, function(id, s) + minetest.register_item(id, { + type = 'none'; + inventory_image = s.tex; + short_description = s.name; + description = starlit.ui.tooltip { + title = s.name; + color = s.color; + desc = s.desc; + }; + on_place = function() + -- FIXME sow + end; + _starlit = { + seed = s; + mass = s.mass; + }; + }) +end) Index: mods/starlit/interfaces.lua ================================================================== --- mods/starlit/interfaces.lua +++ mods/starlit/interfaces.lua @@ -120,11 +120,11 @@ local function abilityMenu(a) -- select primary/secondary abilities or activate ritual abilities local p = {kind = 'vert'} for _, o in ipairs(a.order) do local m = a.menu[o] - table.insert(p, {kind='label', text=m.label, w=a.w, h = .5}) + table.insert(p, {kind='hbar', fac=0.5, text=string.format("%s",m.label), w=a.w, h = .5}) table.insert(p, wrapMenu(a.w, a.h, 1.2, 2, m.opts)) end return p end @@ -461,23 +461,211 @@ end; }; }; }) +-- TODO destroy suit interfaces when power runs out or suit/chip is otherwise disabled starlit.interface.install(starlit.type.ui { id = 'starlit:compile-matter-component'; + sub = { + suit = function(state, user, evt) + if evt.kind == 'disrobe' then state:close() + elseif evt.kind == 'power' and evt.mode == 'off' then state:close() end + end; + playerInventory = function(state,user) + -- refresh + end; + }; pages = { index = { setupState = function(state, user, ctx) - if ctx.context == 'suit' then - end state.pgm = ctx.program + state.select = {} + local E = starlit.mod.electronics + if ctx.context == 'suit' then + state.fetch = function() + local cst = user.entity:get_inventory():get_list 'starlit_suit_chips' + local cl = {order={}, map={}} + for i, c in ipairs(cst) do + if not c:is_empty() then + local d = E.chip.read(c) + local co = { + stack = c; + data = d; + } + table.insert(cl.order, co) + cl.map[d.uuid] = co + end + end + if state.select.chip and not cl.map[state.select.chip.data.uuid] then + -- chip no longer available + user:suitSound 'starlit-error' + state.select = {} + end + state.select.chips = cl + + state.select.scms = {} + if state.select.chip then + state.select.scms = E.chip.usableSoftware({state.select.chip.stack},nil, + function(s) return s.sw.kind == 'schematic' end) + end + end + end + end; + + onClose = function(state, user) + user:suitSound 'starlit-quit' + end; + handle = function(state, user, q) + local sel = state.select + state.fetch() + local chips = state.select.chips + local function chirp() + user:suitSound 'starlit-nav' + end + local function onPickChip(chip) + chirp() + sel.chip = chip + return true + end + local function onPickScm(scm) + chirp() + sel.scm = scm + return true + end + + if sel.chip == nil then + for k in next, q do + local id = k:match "^chip_(%d+)$" + if id then + local cm = chips.map[tonumber(id)] + if cm then return onPickChip(cm) end + end + end + elseif sel.scm == nil then + if q.back then chirp() sel.chip = nil return true end + for k in next, q do + local id = k:match "^scm_(%d+)$" + if id then + local cm = state.select.scms[tonumber(id)] + if cm then return onPickScm(cm) end + end + end + else + if q.back then chirp() sel.scm = nil return true end + end end; + render = function(state, user) + local sel, pgmSelector = state.select, {} + state.fetch() + + local function pushSelector(id, item, label, desc, req) + local rh = .5 + local label = {kind = 'text', w = 10-1.5, h=1.5; + text = ''..label } + if req then + label.h = label.h - rh - .2 + + local imgs = {} + for ci,c in ipairs(req) do + for ei, e in ipairs(c.list) do + table.insert(imgs, {kind = 'img', w=rh, h=rh, img=e.img}) + end + end + label = {kind = 'vert', w = 10-1.5, h=1.5; + label; + {kind ='hztl', w=10-1.5, h=rh; unpack(imgs); } + } + end + table.insert(pgmSelector, {kind = 'hztl', w=10,h=1.5; + {kind = 'contact', id=id, w=1.5, h=1.5; + item = item; + color = {hue=220, sat=0, lum=0}; + desc = desc; + }; + label; + }) + end + + local back = {kind = 'button', id='back', label = '<- Back', w=10,h=1.2} + if sel.chips == nil then + table.insert(pgmSelector, {kind = 'img', img = 'starlit-ui-alert.png', w=2, h=2}) + elseif sel.chip == nil then + for i, c in ipairs(sel.chips.order) do + -- TODO filter out chips without schematics? + pushSelector('chip_' .. c.data.uuid, c.stack, c.data.label) + end + else + if sel.scm == nil then + for idx, ent in ipairs(sel.scms) do + local fab = ItemStack(ent.sw.output):get_definition()._starlit.fab + if fab.flag.print then + local req = fab:visualize() + pushSelector('scm_' .. idx, ent.sw.output, ent.sw.name, nil, req) + end + end + table.insert(pgmSelector, back) + else + local output = ItemStack(sel.scm.sw.output):get_definition() + local fab = output._starlit.fab + local sw = sel.scm.sw + table.insert(pgmSelector, {kind = 'hztl', w=10, h=1.2; + {kind = 'img', item = sw.output, w=1.2, h=1.2, desc=output.description}; + {kind = 'text', text = string.format('%s', sw.name), w=10-1.2,h=1.2}; + }) + local inputTbl = {kind = 'vert', w=5,h=0; + {kind = 'hbar', w=5, h=.5, text='Input'}}; + local costTbl = {kind = 'vert', w=5,h=0; spacing=.25; + {kind = 'hbar', w=5, h=.5, text='Process'}}; + local reqPane = {kind = 'pane', id='reqPane', w=10, h=7; + {kind = 'hztl', w=10,h=0; inputTbl, costTbl} + } + local req = fab:visualize() + for ci,c in ipairs(req) do + table.insert(inputTbl, {kind = 'label', w=4.5, h=1, x=.5; + text=lib.str.capitalize(c.header)}); + for ei,e in ipairs(c.list) do + table.insert(inputTbl, {kind = 'hztl', w=4, h=.5, x=1; + {kind='img', w=.5,h=.5, img=e.img}; + {kind='label', w=3.3,h=.5,x=.2, text=e.label}; + }); + end + end + if sw.cost then + local function pushCost(t, val) + table.insert(costTbl, {kind='text', w=4.5,h=.5,x=.5; + text=string.format('%s: %s',t,val); + }) + end + if sw.cost.cycles then + pushCost('Energy', lib.math.siUI('J', sel.scm.powerCost)) + pushCost('Compute', lib.math.siUI({'cycle','cycles'}, sw.cost.cycles, true)) + end + end + table.insert(pgmSelector, reqPane) + table.insert(pgmSelector, {kind = 'hztl', w=10,h=1.2; + {kind = 'button', id='back', label = '<- Back', w=5,h=1.2}; + {kind = 'button', id='print', label = 'Print ->', w=5,h=1.2, color={hue=120,sat=0,lum=0}}; + }) + end + end + return starlit.ui.build { - kind = 'vert', padding = 0.5; w = 5, h = 5, mode = 'sw'; - {kind = 'label', w = 4, h = 1, text = 'hello'}; + kind = 'hztl', padding = 0.5; w = 20, h = 10, mode = 'sw'; + {kind = 'vert', w = 5, h = 5; + {kind = 'hbar', fac=0, w = 5, h = .5, text = 'Recent Prints'}; + }; + {kind = 'vert', w = 10, h = 10; + {kind = 'hbar', fac=0, w = 10, h = .5, text = 'Program Select'}; + {kind = 'pane', w = 10, h = 9.5, id='pgmSelect'; + unpack(pgmSelector) + }; + }; + {kind = 'vert', w = 5, h = 10; + {kind = 'hbar', fac=0, w = 5, h = .5, text = 'Print Queue'}; + }; } end; }; }; }) Index: mods/starlit/species.lua ================================================================== --- mods/starlit/species.lua +++ mods/starlit/species.lua @@ -107,11 +107,11 @@ metabolism = .150; -- kCal/s painTolerance = 0.4; dehydration = 10e-4; -- L/s speed = 1.1; staminaRegen = 10.0; - psiRegen = 1.3; + psiRegen = 0.05; -- ψ/s psiPower = 1.2; }; }; male = { name = 'Human Male'; @@ -128,11 +128,11 @@ lungCapacity = 1.0; sturdiness = 0.3; metabolism = .150; -- kCal/s dehydration = 15e-4; -- L/s speed = 1.0; - psiRegen = 1.0; + psiRegen = 0.025; psiPower = 1.0; }; }; }; traits = {}; Index: mods/starlit/stats.lua ================================================================== --- mods/starlit/stats.lua +++ mods/starlit/stats.lua @@ -20,12 +20,12 @@ local function C(h, s, l) return lib.color {hue = h, sat = s or 1, lum = l or .7} end starlit.world.stats = { - psi = {min = 0, max = 500, base = 0, desc = U('ψ', 10), color = C(320), name = 'numina'}; - -- numina is measured in daψ + psi = {min = 0, max = 500, base = 0, desc = U('ψ', 1), color = C(320), name = 'numina', srzType = T.decimal}; + -- numina is measured in ψ warmth = {min = -1000, max = 1000, base = 0, desc = U('°C', 10, true), color = C(5), name = 'warmth'}; -- warmth in measured in d°C fatigue = {min = 0, max = 76 * 60, base = 0, desc = U('hr', 60, true), color = C(288,.3,.5), name = 'fatigue', harm=true, srzType = T.decimal}; -- fatigue is measured in minutes one needs to sleep to cure it stamina = {min = 0, max = 10 * 20, base = true, desc = U('m', 100), color = C(88), name = 'stamina'}; Index: mods/starlit/ui.lua ================================================================== --- mods/starlit/ui.lua +++ mods/starlit/ui.lua @@ -31,10 +31,12 @@ if not state then state = { page = page or 'index'; form = self.id; + self = self; + close = function() self:close(user) end; } starlit.activeUI[user.name] = state self:cb('setupState', user, ...) elseif page ~= nil and state.page ~= page then state.page = page @@ -150,10 +152,29 @@ state.x=state.x + state.spacing + st.w state.h = math.max(state.h, st.h) end state.h = state.h + state.padding state.w = state.x + state.padding/2 + elseif def.kind == 'pane' then + widget('scroll_container[%s,%s;%s,%s;%s;vertical]', + state.x, state.y, state.w, state.h, + def.id) + local y = 0 + for _, w in ipairs(def) do + local src, st = starlit.ui.build(w, state) + widget('container[%s,%s]%scontainer_end[]', 0, y, src) + y=y + state.spacing + st.h + state.w = math.max(state.w, st.w) + end + widget('scroll_container_end[]') + if y > state.h then + widget('scrollbar[%s,%s;%s,%s;vertical;%s;]', + state.x, state.y, .5, state.h, + def.id) + end + state.w = state.w + state.padding + state.h = state.h + state.padding/2 elseif def.kind == 'list' then local slotTypes = { plain = {hue = 200, sat = -.1, lum = 0}; element = {hue = 20, sat = -.3, lum = 0}; chip = {hue = 0, sat = -1, lum = 0}; @@ -183,14 +204,24 @@ local sm = 1 state.w = def.w * sm + (spac * (def.w - 1)) state.h = def.h * sm + (spac * (def.h - 1)) elseif def.kind == 'contact' then if def.color then table.insert(lines, btnColorDef(def.id)) end - widget('image_button%s[%s,%s;%s,%s;%s;%s;%s]', + local img = def.img + local desc + if def.item then + img = ItemStack(def.item):get_name() + desc = ItemStack(def.item):get_description() + end + widget('%simage_button%s[%s,%s;%s,%s;%s;%s;%s]', + def.item and 'item_' or '', def.close and '_exit' or '', state.x, state.y, def.w, def.h, - E(def.img), E(def.id), E(def.label or '')) + E(img), E(def.id), E(def.label or '')) + if desc and not def.desc then + widget('tooltip[%s;%s]', E(def.id), E(desc)) + end elseif def.kind == 'button' then if def.color then table.insert(lines, btnColorDef(def.id)) end local label = E(def.label or '') if state.fg then label = lib.color(state.fg):fmt(label) end widget('button%s[%s,%s;%s,%s;%s;%s]', @@ -212,11 +243,11 @@ state.x, state.y, def.w, def.h, E(def.id), E(def.text)) elseif def.kind == 'hbar' or def.kind == 'vbar' then -- TODO fancy image bars local cl = lib.color(state.color) local fg = state.fg or cl:readable(.8,1) local wfac, hfac = 1,1 - local clamp = math.min(math.max(def.fac, 0), 1) + local clamp = math.min(math.max(def.fac or 0, 0), 1) if def.kind == 'hbar' then wfac = wfac * clamp else hfac = hfac * clamp end local x,y, w,h = state.x, state.y, def.w, def.h @@ -230,12 +261,17 @@ string.format('%s', fg:hex(), E(def.text))) end end if def.desc then - widget('tooltip[%s,%s;%s,%s;%s]', - state.x, state.y, def.w, def.h, E(def.desc)) + local coord + if def.id then + coord = E(def.id) + else + coord = string.format("%s,%s;%s,%s", state.x, state.y, def.w, def.h) + end + widget('tooltip[%s;%s;#000000;#ffffff]', coord, E(def.desc)) end local originX = (parent and parent.x or 0) local originY = (parent and parent.y or 0) local l = table.concat(lines) Index: mods/vtlib/math.lua ================================================================== --- mods/vtlib/math.lua +++ mods/vtlib/math.lua @@ -40,39 +40,52 @@ {6, 'M', 'mega', true, 'μ', 'micro', true}; {3, 'k', 'kilo', true, 'm', 'milli', true}; {2, 'h', 'hecto', false, 'c', 'centi', true}; {1, 'da','deca', false, 'd', 'deci', false}; } + + local function unitForAmt(n) + if type(unit)=='table' then + if n == 1 + then return unit[1] + else return unit[2] + end + end + return unit + end + for i, s in ipairs(scales) do local amt, smaj, pmaj, cmaj, smin, pmin, cmin = lib.tbl.unpack(s) + if math.abs(val) > 1 then if uncommonScales or cmaj then local denom = 10^amt local vd = val/denom if prec then vd = lib.math.trim(vd, prec) end if math.abs(val) >= (10^(amt)) then return string.format("%s%s%s", - vd, (full and (' ' .. pmaj) or smaj), unit) + vd, (full and (' ' .. pmaj) or smaj), unitForAmt(vd)) end end elseif math.abs(val) < 1 then if uncommonScales or cmin then local denom = 10^-amt local vd = val/denom if prec then vd = lib.math.trim(vd, prec) end if math.abs(val) <= (10^-(amt-1)) then return string.format("%s%s%s", - vd, (full and (' ' .. pmin) or smin), unit) + vd, (full and (' ' .. pmin) or smin), unitForAmt(vd)) end end end end - return string.format("%s%s", val, unit) + return string.format("%s%s", val, unitForAmt(val)) end +function fn.siUI(u,v,f,us,...) return fn.si(u,v,f,us,2,...) end function fn.lerp(t, a, b) return (1-t)*a + t*b end function fn.gradient(grad, pos) local n = #grad if n == 1 then return grad[1] end ADDED src/sfx/alarm-urgent.csd Index: src/sfx/alarm-urgent.csd ================================================================== --- src/sfx/alarm-urgent.csd +++ src/sfx/alarm-urgent.csd @@ -0,0 +1,21 @@ +; [ʞ] alarm-urgent.csd +; ~ lexi hale +; 🄯 CC-NC-BY-SA 3.0 +; ? VERY angry blarp fer when the bad is done to ya + + + + +#include "dqual.inc" +#include "digital.orc" + + + +i"chirp" 0.00 0.20 0.20 30 1700 +i"chirp" 0.20 0.40 0.20 5 1000 +i"blare" 0.10 0.40 0.8 +i"blarp" 0.40 0.70 0.6 +e 0.9 + + + ADDED src/sfx/alarm.csd Index: src/sfx/alarm.csd ================================================================== --- src/sfx/alarm.csd +++ src/sfx/alarm.csd @@ -0,0 +1,19 @@ +; [ʞ] alarm.csd +; ~ lexi hale +; 🄯 CC-NC-BY-SA 3.0 +; ? angry blarp fer when the bad is done to ya + + + + +#include "dqual.inc" +#include "digital.orc" + + + +i"chirp" 0.00 0.40 0.20 5 1000 +i"blarp" 0.20 0.70 0.6 +e 0.9 + + + ADDED src/sfx/quit.csd Index: src/sfx/quit.csd ================================================================== --- src/sfx/quit.csd +++ src/sfx/quit.csd @@ -0,0 +1,19 @@ +; [ʞ] quit.csd +; ~ lexi hale +; 🄯 CC-NC-BY-SA 3.0 +; ? choopy chorp for when ya log the off + + + + +#include "dqual.inc" +#include "digital.orc" + + + +i"chirp" 0.00 0.10 0.10 20 4000 +i"chirp" 0.15 0.20 0.10 20 2000 +e 0.3 + + +