starlit  Diff

Differences From Artifact [c1a1690c3b]:

To Artifact [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   })