local lib = starlit.mod.lib
local T,G = lib.marshal.t, lib.marshal.g
local function U(unit, prec, fixed)
local trunc = 2
if fixed then
return function(amt, excludeUnit)
local ta = lib.math.trim(amt/prec, trunc)
if excludeUnit then return tostring(ta) end
return string.format("%s%s", ta, unit)
end
else
return function(amt, excludeUnit)
local ta = lib.math.trim(amt/prec, trunc)
if excludeUnit then return tostring(ta) end
return lib.math.si(unit, amt/prec, nil, nil, trunc)
end
end
end
local function C(h, s, l)
return lib.color {hue = h, sat = s or 1, lum = l or .7}
end
starlit.world.stats = {
numina = {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,1,.8), 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', 10), color = C(88), name = 'stamina'};
-- stamina is measured in how many 10th-nodes (== cm) one can sprint
nutrition = {min = 0, max = 8000, base = 0, desc = U('kCal', 1, true), color = C(43,1,.8), name = 'nutrition', srzType = T.decimal};
-- hunger is measured in kcalories one must consume to cure it. at 0, you start dying
hydration = {min = 0, max = 4, base = 0, desc = U('L', 1), color = C(217), name = 'hydration', srzType = T.decimal};
-- thirst is measured in L of H²O required to cure it
morale = {min = 0, max = 10 * 24 * 60, base = true, color = C(0,0,.8), name = 'morale', srzType = T.decimal;
desc = function(amt, excU) return lib.math.timespec(amt) end};
-- morale is measured in minutes. e.g. at base rate morale degrades by
-- 60 points every hour. morale can last up to 10 earthdays
irradiation = {min = 0, max = 10, base = 0, desc = U('Gy', 1), color = C(141,1,.5), name = 'irradiation', harm=true, srzType = T.decimal};
-- irrad is measured is milligreys
-- 1Gy counters natural healing
-- ~3Gy counters basic nanomedicine
-- 5Gy causes death within two weeks without nanomedicine
-- radiation speeds up psi regen
-- morale drain doubles with each 2Gy
illness = {min = 0, max = 1, base = 0, desc = U('%', .01, true), color = C(71,.4,.25), name = 'illness', harm=true, srzType = T.factor};
-- as illness increases, maximum stamina and health gain a corresponding limit
-- illness is increased by certain conditions, and decreases on its own as your
-- body heals when those conditions wear off. some drugs can lower accumulated illness
-- but illness-causing conditions require specific cures
-- illness also causes thirst and fatigue to increase proportionately
}
starlit.world.statOrder = {
'health', 'stamina', 'numina', 'warmth';
'nutrition', 'hydration', 'irradiation';
'illness', 'morale', 'fatigue';
}
local impactStruct = G.struct {
base = G.array(8, G.struct {id = T.str, val = T.decimal});
-- alt = G.array(8, )
}
starlit.type.impact = lib.class {
__name = 'starlit.type.impact';
construct = function(p)
-- deltaPack {
-- nutrition = 5.0;
-- hydration = -1;
-- {"Taste", 'good'; {'morale', 1}};
-- {"Narcotic", 'mixed'; {'morale', 10};
-- {'addiction', function(user) ... end}};
-- {"Magic", 'info'; 'casts an magic spell', function(user) ... end};
-- }
return p
end;
-- __tostring = function(me)
-- end;
__index = {
pushProps = function(me, p)
for i,k in pairs(starlit.world.statOrder) do
if me[k] then
local s = starlit.world.stats[k]
local v = me[k]
local good = v > 0
if s.harm then good = not good end
local d = s.desc(v)
if v > 0 then d = '+' .. d end
table.insert(p, {
title = lib.str.capitalize(s.name);
affinity = good and 'good' or 'bad';
desc = d;
})
end
end
for i,v in ipairs(me) do
local label, aff = v[1], v[2]
local effectStrs = {}
for i = 3, #v do
local t = v[i]
local str
if type(t) == 'table' then
local id, amt = t[1], t[2]
local s = starlit.world.stats[id]
local desc = s.desc(amt)
if amt > 0 then desc = '+' .. desc end
str = string.format('%s to %s', desc, s.name)
-- elseif type(v[i]) == 'function' then
elseif type(t) == 'string' then
str = t
end
if str then table.insert(effectStrs, str) end
end
table.insert(p, {
title = lib.str.capitalize(label);
affinity = aff;
desc = next(effectStrs) and table.concat(effectStrs, ', ') or nil;
})
end
end;
propTable = function(me)
local t = {}
me:pushProps(t)
return t
end;
addToItem = function(me, stack, key)
key = key or 'starlit:impact'
local m = stack:get_meta()
local tbl = {base={}}
for k,v in pairs(me) do
if type(k) == 'string' then
tbl.base[k] = v
end
end
local armored = lib.str.meta_armor(impactStruct.enc(tbl))
m:set_string(key, armored)
return stack
end;
effective = function(me, stack, key)
key = key or 'starlit:impact'
local c = starlit.type.impact.clone(me)
local m = stack:get_meta()
if m:contains(key) then
local tbl = impactStruct.dec(lib.str.meta_dearmor(m:get_string(key)))
for k,v in pairs(tbl.base) do c[k] = v end
end
return c
end;
apply = function(me, user)
for k,v in pairs(me) do
if starlit.world.stats[k] then
user:statDelta(k, v)
elseif type(k) == 'number' then
for i = 3, #v do
local t = v[i]
if type(t) == 'table' then
local id, amt = t[1], t[2]
user:statDelta(id, amt)
elseif type(t) == 'function' then
t(user)
end
end
end
end
end;
};
}