-- [ʞ] 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)
minetest.check_for_falling(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};
})
local function matterCompiler(desc)
return {
name = desc.name;
kind = 'suitPower', powerKind = 'direct';
desc = desc.desc;
size = desc.size;
cost = desc.cost;
ui = 'starlit:compile-matter-component';
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 conf = ctx.file.body.conf
local job_t = starlit.store.compilerJob
local job, jobSlot
for i, v in ipairs(conf) do
if v.key == 'job' then
job = job_t.dec(v.value)
jobSlot = i
goto found
end
end
::notfound:: do
return
end
::found::
local scm = starlit.item.sw.db[job.schematic]
local stages = {
{id = 'cyclesLeft', decr=ctx.comp.cycles};
{id = 'powerLeft', decr=function(current)
return ctx.drawCurrent(current, interval, 'compile')
end};
{id = 'timeLeft', decr=interval};
{id = 'numinaLeft', decr=0}; -- FIXME
}
for i,v in ipairs(stages) do
if job[v.id] > 0 then
local decr
if type(v.decr) == 'function'
then decr = v.decr(job[v.id])
else decr = v.decr
end
job[v.id] = math.max(0, job[v.id] - decr)
goto incomplete
end
end
::complete:: do
table.remove(conf, jobSlot)
user:give(scm.output)
user:alarm(-2, 'item')
goto done
end
::incomplete:: do
conf[jobSlot].value = job_t.enc(job)
end
::done::
ctx.saveConf()
end;
}
end
starlit.item.sw.link('starlit_electronics:compile_commune', matterCompiler {
name = 'Compile Matter';
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.";
size = 700e6;
cost = {
cycles = 4e9;
ram = .3e9;
};
})
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 = 500e6;
cost = {
cycles = 8e9;
ram = 1e9;
};
ui = 'starlit:compile-matter-block';
run = function(user, ctx)
end;
})
starlit.item.sw.link('starlit_electronics:compile_imperial', matterCompiler {
name = 'Genesis Deluxe';
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'.";
size = 2e9;
cost = {
cycles = 1e9;
ram = 1.5e9;
};
})
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);
})
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);
})