Index: mods/starlit-electronics/init.lua ================================================================== --- mods/starlit-electronics/init.lua +++ mods/starlit-electronics/init.lua @@ -235,10 +235,11 @@ end]] E.battery.update(st) end; }; fab = def.fab; + reverseEngineer = def.reverseEngineer; dynamo = { vtable = E.dynamo.kind.battery; }; battery = def; }; @@ -486,14 +487,10 @@ return bType[s] * (bTier[s] or 1) * (bSize[s] or 1) end end local swID = 'starlit_electronics:schematic_'..baseID - fab.reverseEngineer = { - complexity = bTier.complexity * bSize.complexity * bType.complexity; - sw = swID; - } fab.flag = {print=true} starlit.item.battery.link(id, { name = name; desc = table.concat({ @@ -501,10 +498,14 @@ bTier.desc or ''; bSize.desc or ''; }, ' '); fab = fab; + reverseEngineer = { + complexity = bTier.complexity * bSize.complexity * bType.complexity; + sw = swID; + }; capacity = batStat 'capacity'; dischargeRate = batStat 'dischargeRate'; leak = batStat 'leak'; decay = batStat 'decay'; @@ -542,12 +543,12 @@ E.sw = {} function E.sw.findSchematicFor(item) local id = ItemStack(item):get_name() local fm = minetest.registered_items[id]._starlit - if not (fm and fm.fab and fm.fab.reverseEngineer) then return nil end - local id = fm.fab.reverseEngineer.sw + if not (fm and fm.reverseEngineer) then return nil end + local id = fm.reverseEngineer.sw return id, starlit.item.sw.db[id] end E.chip = { file = {} } do local T,G = lib.marshal.t, lib.marshal.g @@ -614,11 +615,11 @@ for _, e in pairs(file.body.entries) do sz = sz + #e.title + #e.body + 0x10 -- header overhead end return sz elseif file.kind == 'research' then - local re = assert(minetest.registered_items[file.body.itemId]._starlit.fab.reverseEngineer) + local re = assert(minetest.registered_items[file.body.itemId]._starlit.reverseEngineer) return starlit.item.sw.db[re.sw].size * file.body.progress elseif file.kind == 'sw' then return starlit.item.sw.db[file.body.pgmId].size elseif file.kind == 'genome' then return 0 -- TODO @@ -855,11 +856,11 @@ for _, e in pairs(chips) do n = n + 1 if not e:is_empty() then local ch = e:get_definition()._starlit.chip c.cycles = c.cycles + ch.clockRate - c.ram = c.ram + ch.clockRate + c.ram = c.ram + ch.ram c.flashFree = c.flashFree + E.chip.freeSpace(e) c.powerEfficiency = c.powerEfficiency + ch.powerEfficiency end end if n > 0 then c.powerEfficiency = c.powerEfficiency / n end Index: mods/starlit-electronics/sw.lua ================================================================== --- mods/starlit-electronics/sw.lua +++ mods/starlit-electronics/sw.lua @@ -172,10 +172,11 @@ job.timeLeft = math.max(0, job.timeLeft - interval) end if job.timeLeft == 0 and job.cyclesLeft == 0 then table.remove(conf, jobSlot) user:give(scm.output) + user:alarm(-2, 'item') else conf[jobSlot].value = job_t.enc(job) end ctx.saveConf() @@ -327,5 +328,18 @@ cycles = 700e6; ram = 1e9; }; run = pasv_heal(4, 50, .7); }) + +starlit.item.sw.link('starlit_electronics:battle_buddy_extreme', { + name = 'BattleBuddy XTREME'; + kind = 'suitPower', powerKind = 'passive'; + desc = "Who needs a unit medic when you've got BattleBuddy XTREME Edition! BattleBuddy XTREME Edition is fully loaded with emergency response protocols for wounds of every caliber, and is GUARANTEED* to keep you alive as long as you can still crawl to safety. BattleBuddy XTREME is not intended for civilian use. By using BattleBuddy XTREME, you commit to unbind House Vacsatar, its subcontractors, and cadet houses from all liability for product failure, intracellular mutilation, transcription drift, runaway prion cascades, or military defeat.\n*Guarantees not legally binding."; + size = 4e9; + cost = { + cycles = 2000e6; + ram = 8e9; + }; + run = pasv_heal(4, 50, .7); +}) + Index: mods/starlit-scenario/init.lua ================================================================== --- mods/starlit-scenario/init.lua +++ mods/starlit-scenario/init.lua @@ -32,34 +32,41 @@ r.label = label r.files = files E.chip.write(chip, r) return chip end + +local survivalBasics = { + {'starlit_tech:chem_lamp', 0}; + {'starlit_tech:crate', 0}; +} local chipLibrary = { - compendium = makeChip('The Gentleman Adventurer\'s Compleat Wilderness Compendium', { + compendium = makeChip('The Gentleman Adventurer\'s Compleat Wilderness Compendium', lib.tbl.append(survivalBasics, { {'starlit_electronics:battery_chemical_imperial_small', 0}; - }, { + }), { {'starlit_electronics:shred', 0}; - --{'starlit_electronics:compile_empire', 0}; + {'starlit_electronics:compile_imperial', 0}; {'starlit_electronics:autodoc_deluxe', 1}; --{'starlit_electronics:driver_compiler_empire', 0}; }); - survivalware = makeChip('Emergency Survivalware', { + survivalware = makeChip('Emergency Survivalware', lib.tbl.append(survivalBasics, { {'starlit_electronics:battery_chemical_commune_small', 0}; - {'starlit_tech:chem_lamp', 0}; - }, { + }), { {'starlit_electronics:shred', 0}; {'starlit_electronics:compile_commune', 0}; {'starlit_electronics:nanomed', 0}; {'starlit_electronics:driver_compiler_commune', 0}; }); misfortune = makeChip("Sold1er0fMisf0rtune TOP Schematic Crackz REPACK", { + {'starlit_tech:chem_lamp', 0}; {'starlit_electronics:battery_chemical_usukwinya_mid', 0}; {'starlit_electronics:battery_hybrid_imperial_small', 0}; -- ammunition - }, {}); + }, { + {'starlit_electronics:battle_buddy_extreme', 1}; -- + }); } local battery = function(name) local s = ItemStack(name) starlit.mod.electronics.battery.setChargeF(s, 1.0) Index: mods/starlit-scenario/mod.conf ================================================================== --- mods/starlit-scenario/mod.conf +++ mods/starlit-scenario/mod.conf @@ -1,5 +1,5 @@ name = starlit_scenario title = starlit scenarios description = built-in scenarios for Starsoul -depends = starlit, starlit_suit, starlit_electronics, starlit_building, starlit_material +depends = vtlib, starlit, starlit_suit, starlit_electronics, starlit_building, starlit_material, starlit_tech # be sure to add any mods from which you list new starting items! Index: mods/starlit-tech/init.lua ================================================================== --- mods/starlit-tech/init.lua +++ mods/starlit-tech/init.lua @@ -13,14 +13,10 @@ local fab = starlit.type.fab { element = { carbon = 8, magnesium = 2 }; cost = { power = 100 }; flag = { print = true }; time = { print = 5 }; - reverseEngineer = { - complexity = 1; - sw = 'starlit_tech:schematic_chem_lamp'; - }; }; for i = stages, 0, -1 do minetest.register_node(chemLampID(i), { short_description = 'Chem Lamp'; description = starlit.ui.tooltip { @@ -32,11 +28,11 @@ {title = 'Mass', desc='10g', affinity='info'}; }; }; drawtype = 'nodebox'; groups = { - object = 2; + object = 1; attached_node = 1; }; node_box = { type = 'fixed'; fixed = { @@ -63,11 +59,14 @@ minetest.swap_node(pos, {name=chemLampID(i-1), param2=me.param2}) return i > 1 end or nil; _starlit = { mass = 10; - fab = fab; + reverseEngineer = { + complexity = 1; + sw = 'starlit_tech:schematic_chem_lamp'; + }; recover = starlit.type.fab { element = { carbon = 8; magnesium = math.floor(lib.math.lerp(i/stages, 0, 2)); }; @@ -91,5 +90,84 @@ ram = 16e6; }; rarity = 1; }) end + + +minetest.register_node('starlit_tech:crate', { + short_description = 'Crate'; + description = starlit.ui.tooltip { + title = 'Crate'; + desc = 'A sturdy but lightweight storage crate made from solid carbon polymer.'; + props = { {title='Mass', affinity='info', desc='100g'} }; + }; + drawtype = 'nodebox'; + node_box = { + type = 'fixed'; + fixed = { + .4, .2, .4; + -.4, -.5, -.2; + }; + }; + groups = { + object = 3; + attached_node = 3; + }; + paramtype2 = 'facedir'; + tiles = { + 'starlit-tech-crate-top.png'; + 'starlit-tech-crate-bottom.png'; + + 'starlit-tech-crate-side.png^[transformFX'; + 'starlit-tech-crate-side.png'; + + 'starlit-tech-crate-back.png'; + 'starlit-tech-crate-front.png'; + }; + _starlit = { + mass = 100; + reverseEngineer = { + complexity = 1; + sw = 'starlit_tech:schematic_crate'; + }; + recover = starlit.type.fab { + element = { carbon = 100; }; + time = { + shred = 1; + shredPower = 3; + }; + }; + }; + on_construct = function(pos) + local m = minetest.get_meta(pos) + local inv = m:get_inventory() + inv:set_size('starlit:contents', 12) + end; + on_rightclick = function(pos, node, luser) + if not luser then return end + local user = starlit.activeUsers[luser:get_player_name()] + user:openUI('starlit:box', 'index', { + inv={ + {id = 'starlit:contents', pos=pos}; + }; + }) + end; +}) + +starlit.item.sw.link('starlit_tech:schematic_crate', { + name = 'Crate Schematic'; + kind = 'schematic'; + input = starlit.type.fab { + element = { carbon = 100; }; + flag = {print = true}; + time = {print = 25}; + cost = {power = 250}; + }; + output = 'starlit_tech:crate'; + size = 48e6; + cost = { + cycles = 12e9; + ram = 16e6; + }; + rarity = 1; +}) Index: mods/starlit/compile.lua ================================================================== --- mods/starlit/compile.lua +++ mods/starlit/compile.lua @@ -316,11 +316,11 @@ }) 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 + local fab = ent.sw.input if fab.flag and fab.flag.print then local req = fab:visualize() pushSelector('scm_' .. idx, ent.sw.output, ent.sw.name, nil, req) end end Index: mods/starlit/init.lua ================================================================== --- mods/starlit/init.lua +++ mods/starlit/init.lua @@ -401,11 +401,11 @@ type = "none", wield_image = "wieldhand.png", wield_scale = {x=1,y=1,z=2.5}, tool_capabilities = { groupcaps = { - object = {maxlevel=1, times = {.20,.10}}; + object = {maxlevel=1, times = {.10,.20,.40}}; plant = {maxlevel=1, times = {.50}}; -- sand, dirt, gravel looseClump = {maxlevel=1, times = {1.5, 2.5}}; }; Index: mods/starlit/interfaces.lua ================================================================== --- mods/starlit/interfaces.lua +++ mods/starlit/interfaces.lua @@ -95,10 +95,11 @@ fg = i.fg; label = i.label; img = i.img; id = i.id; w = bw, h = rh; + desc = i.desc; }) if i.cfg then table.insert(bar, { kind = 'button'; color = i.color; @@ -308,16 +309,39 @@ fg = lib.color {hue=color.hue,sat=0.7,lum=0.7} break end end end - if tbl then table.insert(tbl, { - color = color, fg = fg; - label = r.sw.label or r.sw.name; - id = string.format('suit_pgm_%s_', id); - cfg = cfg, close = close; - }) end + if tbl then + local props = { + {title = "Size", desc=lib.math.siUI('B', r.sw.size), affinity='info'}; + } + if r.sw.cost and r.sw.cost.ram then + table.insert(props, {title = "Memory Usage", desc=lib.math.siUI('B', r.sw.cost.ram), affinity='info'}) + end + if r.sw.cost and r.sw.cost.cycles then + table.insert(props, {title = "Compute Usage", desc=lib.math.siUI('cycles',r.sw.cost.cycles,true), affinity='info'}) + end + if r.powerCost then + table.insert(props, {title = "Power Draw", desc=lib.math.siUI('W', r.powerCost), affinity='info'}) + end + if r.speed then + table.insert(props, {title = "Minimum Runtime", desc=lib.math.timespec(r.speed), affinity='info'}) + end + table.insert(tbl, { + color = color, fg = fg; + label = r.sw.label or r.sw.name; + id = string.format('suit_pgm_%s_', id); + desc = starlit.ui.tooltip { + title = r.sw.name; + desc = r.sw.desc; + color = lib.color(1,0,.8); + props = props; + }; + cfg = cfg, close = close; + }) + end end end local menu = { kind = 'vert', mode = 'sw', padding = 0.5 } if swm then table.insert(menu, abilityMenu(swm)) end @@ -517,5 +541,41 @@ end end; }; }; }) + +starlit.interface.install(starlit.type.ui { + id = 'starlit:box'; + pages = { + index = { + setupState = function(state, user, ctx) + state.ctx = ctx + end; + handle = function(state, user, q) + if q.quit then + user:suitSound 'starlit-quit' -- TODO better sound + end + end; + render = function(state, user) + local body = {kind='vert', w=6; mode='hw', spacing=.5, padding=1 } + for i, l in ipairs(state.ctx.inv) do + local inv = minetest.get_meta(l.pos):get_inventory() + local w = l.w or 6 + if l.label then + table.insert(body, {kind = 'hbar'; text = l.label, w=w+.5, h = .5}) + end + table.insert(body, {kind = 'list'; + w = w, h = inv:get_size(l.id)/w; + node = l.pos, inv = l.id; + spacing = .1; + }) + end + table.insert(body, {kind = 'list'; + target = 'current_player', inv = 'main'; + w = 6, h = 1, spacing = 0.1; + }) + return starlit.ui.build(body) + end; + } + } +}) Index: mods/starlit/ui.lua ================================================================== --- mods/starlit/ui.lua +++ mods/starlit/ui.lua @@ -133,17 +133,19 @@ climg(':pressed', 'starlit-ui-button-sw-press.png') end local function widget(...) table.insert(lines, string.format(...)) end + local specializedTooltip = false if def.kind == 'vert' then for _, w in ipairs(def) do local src, st = starlit.ui.build(w, state) widget('container[%s,%s]%scontainer_end[]', state.x, state.y, src) state.y=state.y + state.spacing + st.h state.w = math.max(state.w, st.w) end + state.y = state.y - state.spacing state.w = state.w + state.padding state.h = state.y + state.padding/2 elseif def.kind == 'hztl' then for _, w in ipairs(def) do local src, st = starlit.ui.build(w, state) @@ -197,32 +199,36 @@ 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}; +-- element = {hue = 20, sat = -.3, lum = 0}; chip = {hue = 0, sat = -1, lum = 0}; - psi = {hue = 300, sat = 0, lum = 0}; +-- psi = {hue = 300, sat = 0, lum = 0}; power = {hue = 50, sat = 0, lum = .2}; } local img if state.mode == 'hw' then img = lib.image('starlit-ui-slot-physical.png'); else img = lib.image('starlit-ui-slot.png'):shift(slotTypes[def.listContent or 'plain']); end local spac = state.spacing + local target = def.target + if not target and def.node then + target=string.format('nodemeta:%s,%s,%s', def.node.x,def.node.y,def.node.z) + end widget('style_type[list;spacing=%s,%s]',spac,spac) assert(def.w and def.h, 'ui-lists require a fixed size') for lx = 0, def.w-1 do for ly = 0, def.h-1 do local ox, oy = state.x + lx*(1+spac), state.y + ly*(1+spac) table.insert(lines, string.format('image[%s,%s;1.1,1.1;%s]', ox-0.05,oy-0.05, img:render())) end end table.insert(lines, string.format('listcolors[#00000000;#ffffff10]')) -- FIXME table.insert(lines, string.format('list[%s;%s;%s,%s;%s,%s;%s]', - E(def.target), E(def.inv), + E(target), E(def.inv), state.x, state.y, def.w, def.h, def.idx)) local sm = 1 state.w = def.w * sm + (spac * (def.w - 1)) @@ -233,26 +239,32 @@ local desc if def.item then img = ItemStack(def.item):get_name() desc = ItemStack(def.item):get_description() end + desc = def.desc or desc 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(img), E(def.id), E(def.label or '')) - if desc and not def.desc then + if desc then widget('tooltip[%s;%s]', E(def.id), E(desc)) + specializedTooltip = true 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]', def.close and '_exit' or '', state.x, state.y, def.w, def.h, E(def.id), label) + if def.desc then + widget('tooltip[%s;%s]', E(def.id), E(def.desc)) + specializedTooltip = true + end elseif def.kind == 'img' then widget('%s[%s,%s;%s,%s;%s]', def.item and 'item_image' or 'image', state.x, state.y, def.w, def.h, E(def.item or def.img)) elseif def.kind == 'label' then @@ -285,11 +297,11 @@ state.x, state.y, def.w, def.h, string.format('%s', fg:hex(), E(def.text))) end end - if def.desc then + if def.desc and not specializedTooltip then 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) Index: mods/starlit/user.lua ================================================================== --- mods/starlit/user.lua +++ mods/starlit/user.lua @@ -54,10 +54,15 @@ fatigue = { icon = lib.image('starlit-ui-alert-fatigue.png'); bg = lib.image('starlit-ui-alert-bg-fatigue.png'); side = 'right'; }; + item = { + icon = lib.image('starlit-ui-alert-item.png'); + bg = lib.image('starlit-ui-alert-bg-success.png'); + side = 'right'; + }; } starlit.type.user = lib.class { name = 'starlit:user'; leds = leds; @@ -291,13 +296,10 @@ local n = math.floor(v*16) + 1 local function adjust(img) return hudAdjustBacklight(lib.image(img)):shift(color or def.color) end local img = adjust 'starlit-ui-meter.png' - if def.flipX then - img = img:transform 'FX' - end img = img:render() img = img .. '^[verticalframe:17:' .. tostring(17 - n) if hl then hl = math.floor(hl*16) + 1 local hi = hudAdjustBacklight(lib.image 'starlit-ui-meter-hl.png') @@ -305,10 +307,13 @@ :render() hi = hi .. '^[verticalframe:17:' .. tostring(17 - hl) img = string.format('%s^(%s)', img, hi) end img = string.format('%s^(%s)', img, adjust 'starlit-ui-meter-readout.png':render()) + if def.flipX then + img = img .. '^[transformFX' + end luser:hud_change(m.meter, 'text', img) if txt then luser:hud_change(m.readout, 'text', txt) end if txtcolor then Index: mods/vtlib/image.lua ================================================================== --- mods/vtlib/image.lua +++ mods/vtlib/image.lua @@ -13,17 +13,17 @@ str = string.format('[combine:%sx%s', self.w, self.h) for _,i in pairs(self.atop) do str = str .. string.format(':%s,%s=(%s)', i.at.x, i.at.y, i.img:render()) end else - for _,i in pairs(self.atop) do - str = '(' .. i.img:render() .. ')^' .. str - end if str ~= '' then str = str .. '(' bracket = true end + for _,i in pairs(self.atop) do + str = '(' .. i.img:render() .. ')^' .. str + end str = str .. self.string end for _,e in pairs(self.fx) do str = str .. '^[' .. e -- be sure to escape ones that take arguments Index: mods/vtlib/math.lua ================================================================== --- mods/vtlib/math.lua +++ mods/vtlib/math.lua @@ -79,10 +79,11 @@ end end end end + if prec then val = lib.math.trim(val,prec) end 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 @@ -156,10 +157,11 @@ -- function fn.vlerp function fn.timespec(n) if n == 0 then return '0s' end if n < 0 then return '-' .. fn.timespec(n*-1) end + if n < 1 then return fn.siUI('s', n) end local sec = math.floor(n % 60) local min = math.floor(n / 60) local hr = math.floor(min / 60) min = min % 60