starlit  sw.lua at [e829ca194a]

File mods/starlit-electronics/sw.lua artifact eb892cff12 part of check-in e829ca194a


-- [ʞ] sw.lua
--  ~ lexi hale <lexi@hale.su>
--  🄯 EUPL v1.2
--  ? 

-------------------------------
-- basic suit nano abilities --
-------------------------------
local function shredder(prop)
	local function fabToItemsAndCharges(fab)
		local elt
		if fab then
			elt = fab:elementalize()
		else
			elt = {}
		end
		local items,charges = {},{}
		if elt.element then
			for k,v in pairs(elt.element) do
				local forms =  starlit.world.material.element.db[k].form
				if forms.brick then
					local st = ItemStack {
						name = forms.brick;
						count = math.floor(v);
					}
					table.insert(items, st)
				else -- gas, liquid
					table.insert(charges, {id = k, mass = v})
				end
			end
		end
		return items, charges
	end

	return function(user, ctx)
		local function cleanup()
			user.action.prog.shred = nil
			if user.action.sfx.shred then
				minetest.sound_fade(user.action.sfx.shred, 1, 0)
				user.action.sfx.shred = nil
			end
			if user.action.fx.shred then
				user.action.fx.shred.abort()
			end
		end

		if user.action.tgt.type ~= 'node' then return end
		local what = user.action.tgt.under
		if what == nil or user.entity:get_pos():distance(what) > prop.range then
			cleanup()
			return false
		end
		local shredTime = 1.0
		local soundPitch = 1.0 -- TODO
		local pdraw = prop.powerDraw or 0

		if minetest.is_protected(what, user.entity:get_player_name()) then return end
		local node = minetest.get_node(what)
		local nd = minetest.registered_nodes[node.name]
		local elt, fab, vary
		if nd._starlit then
			fab = nd._starlit.recover or nd._starlit.fab
			vary = nd._starlit.recover_vary
		end
		if fab then
			if fab.flag then
				if fab.flag.unshreddable then
					cleanup()
					return false
					-- TODO error beep
				end
			end
			shredTime = fab.time and fab.time.shred or shredTime -- FIXME
			if fab.cost and fab.cost.shredPower then
				pdraw = pdraw * fab.cost.shredPower
			end
		end
		local maxW = user:getSuit():maxPowerUse()
		if maxW < pdraw then
			shredTime = shredTime * (pdraw/maxW)
			pdraw = maxW
		end
		if ctx.how.state == 'prog' then
			local pdx = pdraw * ctx.how.delta
			local p = user:suitDrawCurrent(pdx, ctx.how.delta, {kind='nano',label='Shredder'}, pdx)
			if p < pdx then
				cleanup()
				return false
			elseif not user.action.prog.shred then
				cleanup() -- kill danglers
				-- begin
				user.action.prog.shred = 0
				user.action.sfx.shred = minetest.sound_play('starlit-nano-shred', {
					object = user.entity;
					max_hear_distance = prop.range*2;
					loop = true;
					pitch = soundPitch;
				})
				user.action.fx.shred = starlit.fx.nano.shred(user, what, prop, shredTime, node)
			else
				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)
				--print('shred complete')
				user:suitSound 'starlit-success'
				if fab then
					local vf = fab
					if vary then
						local rng = (starlit.world.seedbank+0xa891f62)[minetest.hash_node_position(what)]
						vf = vf + vary(rng, {})
					end
					local items, charges = fabToItemsAndCharges(vf)
					for i, it in ipairs(items) do user:give(it) end
					-- TODO give gasses, liquids
				end
				cleanup()
			end
		elseif ctx.how.state == 'halt' then
			cleanup()
		end
		return true
	end
end

starlit.item.sw.link('starlit_electronics:shred', {
	name = 'NanoShred';
	kind = 'suitPower', powerKind = 'active';
	desc = 'An open-source program used in its various forks and iterations all across human-inhabited space and beyond. Rumored to contain fragments of code stolen from the nanoware of the Greater Races by an elusive infoterrorist.';
	size = 500e3;
	cost = {
		cycles = 100e6;
		ram = 500e6;
	};
	run = shredder{range=3, powerDraw=200};
})

starlit.item.sw.link('starlit_electronics:compile_commune', {
	name = 'Compile Matter';
	kind = 'suitPower', powerKind = 'direct';
	desc = "A basic suit matter compiler program, rather slow but ruthlessly optimized for power- and memory-efficiency by some of the Commune's most fanatic coders.";
	size = 700e3;
	cost = {
		cycles = 300e6;
		ram = 2e9;
	};
	ui = 'starlit:compile-matter-component';
	run = function(user, ctx)
	end;
})

starlit.item.sw.link('starlit_electronics:compile_block_commune', {
	name = 'Compile Block';
	kind = 'suitPower', powerKind = 'active';
	desc = "An advanced suit matter compiler program, capable of printing complete devices and structure parts directly into the world.";
	size = 5e6;
	cost = {
		cycles = 700e6;
		ram = 4e9;
	};
	ui = 'starlit:compile-matter-block';
	run = function(user, ctx)
	end;
})

do local J = starlit.store.compilerJob
	starlit.item.sw.link('starlit_electronics:driver_compiler_commune', {
		name = 'Matter Compiler';
		kind = 'driver';
		desc = "A driver for a standalone matter compiler, suitable for building larger components than your suit alone can handle.";
		size = 850e3;
		cost = {
			cycles = 400e6;
			ram = 2e9;
		};
		ui = 'starlit:device-compile-matter-component';
		run = function(user, ctx)
		end;
		bgProc = function(user, ctx, interval, runState)
			if runState.flags.compiled == true then return false end
			-- only so many nanides to go around
			runState.flags.compiled = true
			local time = minetest.get_gametime()
			local cyclesLeft = ctx.comp.cycles * interval

			for id, e in ipairs(ctx.file.body.conf) do
				if e.key == 'job' then
					local t = J.dec(e.value)
					local remove = false
					local r = starlit.item.sw.db[t.schematic]
					if not r then -- bad schematic
						remove = true
					else
						local ccost = ctx.sw.cost.cycles + r.cost.cycles
						local tcost = ccost / cyclesLeft
						t.progress = t.progress + (1/tcost)*interval
						cyclesLeft = cyclesLeft - ccost*interval
						if t.progress >= 1 then
							-- complete
							remove = true
							local i = starlit.item.mk(r.output, {
								how = 'print';
								user = user; -- for suit
								compiler = {
									node = ctx.compiler; -- for device
									sw = ctx.sw;
									install = ctx.fd;
								};
								schematic = r;
							})
							ctx.giveItem(i)
						end
					end
					if remove then
						table.remove(ctx.file.body.conf, id)
					else
						e.value = J.enc(t)
					end
					if not cyclesLeft > 0 then break end
				end
			end
			ctx.saveConf()
		end;
	})
end

local function pasv_heal(effect, energy, lvl, pgmId)
	return function(user, ctx, interval, runState)
		if runState.flags.healed == true then return false end
		-- competing nanosurgical programs?? VERY bad idea
		runState.flags.healed = true

		local amt, f = user:effectiveStat 'health'
		local st = user:getSuit():powerState()
		if (st == 'on' and f < lvl) or (st == 'powerSave' and f < math.min(lvl,0.25)) then
			local maxPower = energy*interval
			local p = user:suitDrawCurrent(maxPower, interval, {
				id = 'heal';
				src = 'suitPower';
				pgmId = pgmId;
				healAmount = effect;
			})
			if p > 0 then
				local heal = (p/maxPower) * ctx.speed * effect*interval
				--user:statDelta('health', math.max(1, heal))
				starlit.fx.nano.heal(user, {{player=user.entity}}, heal, 1)
				return true
			end
		end
		return false -- program did not run
	end;
end

starlit.item.sw.link('starlit_electronics:nanomed', {
	name = 'NanoMed';
	kind = 'suitPower', powerKind = 'passive';
	desc = 'Repair of the body is a Commune specialty, and their environment suits all come equipped with highly sophisticated nanomedicine suites, able to repair even the most grievous of wounds given sufficient energy input and time.';
	size = 2e9;
	cost = {
		cycles = 400e6;
		ram = 3e9;
	};
	run = pasv_heal(2, 20, 1);
})

starlit.item.sw.link('starlit_electronics:autodoc_deluxe', {
	name = 'AutoDoc Deluxe';
	kind = 'suitPower', powerKind = 'passive';
	desc = "A flagship offering of the Excellence Unyielding nanoware division, AutoDoc Deluxe has been the top-rated nanocare package in the Celestial Shores Province for six centuries and counting. Every chip includes our comprehensive database of illnesses, prosyn schematics, and organ repair techniques, with free over-the-ether updates guaranteed for ten solariads from date of purchase! When professional medical care just isn't an option, 9/10 doctors recommend Excellence Unyielding AutoDoc Deluxe! The remaining doctor was bribed by our competitors.";
	size = 1e9;
	cost = {
		cycles = 700e6;
		ram = 1e9;
	};
	run = pasv_heal(4, 50, .7);
})