Index: mods/starlit-electronics/sw.lua ================================================================== --- mods/starlit-electronics/sw.lua +++ mods/starlit-electronics/sw.lua @@ -131,11 +131,11 @@ size = 500e3; cost = { cycles = 100e6; ram = 500e6; }; - run = shredder{range=2, powerDraw=200}; + run = shredder{range=3, powerDraw=200}; }) starlit.item.sw.link('starlit_electronics:compile_commune', { name = 'Compile Matter'; kind = 'suitPower', powerKind = 'direct'; Index: mods/starlit/init.lua ================================================================== --- mods/starlit/init.lua +++ mods/starlit/init.lua @@ -48,16 +48,17 @@ }; interface = lib.registry.mk 'starlit:interface'; item = { food = lib.registry.mk 'starlit:food'; + seed = lib.registry.mk 'starlit:seed'; }; region = { radiator = { store = AreaStore(); - emitters = {} + emitters = {}; }; }; -- standardized effects fx = {}; @@ -388,12 +389,14 @@ type = "none", wield_image = "wieldhand.png", wield_scale = {x=1,y=1,z=2.5}, tool_capabilities = { groupcaps = { - plant = {maxlevel=1, times = {.50,.5,.5}}; - dirt = {maxlevel=1, times = {2.5,1,1}}; + plant = {maxlevel=1, times = {.50}}; + dirt = {maxlevel=1, times = {2.5}}; + + log = {maxlevel=1, times = {1}}; }; } }) minetest.register_on_player_inventory_action(function(luser, act, inv, p) @@ -420,20 +423,24 @@ return delta end, true) function minetest.handle_node_drops(pos, drops, digger) local function jitter(pos) - local function r(x) return x+math.random(-0.2, 0.2) end + local function r(x) return x+math.random(-0.01, 0.01) end return vector.new( r(pos.x), r(pos.y), r(pos.z) ) end for i, it in ipairs(drops) do - minetest.add_item(jitter(pos), it) + local it = minetest.add_item(jitter(pos), it) + local dp = vector.new(0,0,0) + if digger then dp = digger:get_pos() end + local delta = dp - it:get_pos() + it:add_velocity(vector.new(delta.x,0,delta.z)); end end -- TODO timer iterates live UI Index: mods/starlit/interfaces.lua ================================================================== --- mods/starlit/interfaces.lua +++ mods/starlit/interfaces.lua @@ -347,11 +347,11 @@ padding = 0.5, {kind = 'hztl', padding = 0.25; {kind = 'label', text = 'Name', w = 2, h = barh}; {kind = 'label', text = user.persona.name, w = 4, h = barh}}; } - local statBars = {'hunger', 'thirst', 'fatigue', 'morale', 'irradiation', 'illness'} + local statBars = {'nutrition', 'hydration', 'fatigue', 'morale', 'irradiation', 'illness'} for idx, id in ipairs(statBars) do local s = starlit.world.stats[id] local amt, sv = user:effectiveStat(id) local min, max = starlit.world.species.statRange(user.persona.species, user.persona.speciesVariant, id) local st = string.format('%s / %s', s.desc(amt, true), s.desc(max)) Index: mods/starlit/species.lua ================================================================== --- mods/starlit/species.lua +++ mods/starlit/species.lua @@ -47,43 +47,43 @@ end; stats = { psiRegen = 1.3; psiPower = 1.2; psi = 1.2; - hunger = .8; -- women have smaller stomachs - thirst = .8; + nutrition = .8; -- women have smaller stomachs + hydration = .8; staminaRegen = 1.0; morale = 0.8; -- you are not She-Bear Grylls }; traits = { health = 400; lungCapacity = .6; irradiation = 0.8; -- you are smaller, so it takes less rads to kill ya sturdiness = 0; -- women are more fragile and thus susceptible to blunt force trauma - metabolism = 1800e3 / 24 / 60 / 60; --kCal/s + metabolism = .150; -- kCal/s painTolerance = 0.4; - dehydration = 3; -- mL/s + dehydration = 10e-4; -- L/s }; }; male = { name = 'Human Male'; eyeHeight = 1.6; stats = { psiRegen = 1.0; psiPower = 1.0; psi = 1.0; - hunger = 1.0; - thirst = 1.0; + nutrition = 1.0; + hydration = 1.0; staminaRegen = .7; -- men are strong but have inferior endurance }; traits = { health = 500; painTolerance = 1.0; lungCapacity = 1.0; sturdiness = 0.3; - metabolism = 2200e3 / 24 / 60 / 60; --Cal/s - dehydration = 5; -- mL/s + metabolism = .150; -- kCal/s + dehydration = 15e-4; -- L/s }; }; }; traits = {}; }; @@ -167,11 +167,11 @@ elseif base == false then base = min end end - return min, max, base + return min, max, base or 0 end -- set the necessary properties and create a persona for a newspawned entity function starlit.world.species.birth(pSpecies, pVariant, entity, circumstances) circumstances = circumstances or {} @@ -186,10 +186,12 @@ local startingHP = pct('health', 1.0) if circumstances.injured then startingHP = pct('health', circumstances.injured) end if circumstances.psiCharged then ps.statDeltas.psi = pct('psi', circumstances.psiCharged) end for k,v in pairs(starlit.world.stats) do ps.statDeltas[k] = 0 end ps.statDeltas.warmth = 20 -- don't instantly start dying of frostbite + ps.statDeltas.nutrition = 2000 -- shoulda packed more MRE :c + ps.statDeltas.hydration = 3 -- stay hydrated uwu entity:set_properties{hp_max = var.traits.health or sp.traits.health} entity:set_hp(startingHP, 'initial hp') return ps end Index: mods/starlit/stats.lua ================================================================== --- mods/starlit/stats.lua +++ mods/starlit/stats.lua @@ -1,14 +1,15 @@ 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) + 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 @@ -22,23 +23,23 @@ end starlit.world.stats = { psi = {min = 0, max = 500, base = 0, desc = U('ψ', 10), color = C(320), name = 'Numina'}; -- numina is measured in daψ warmth = {min = -1000, max = 1000, base = 0, desc = U('°C', 10, true), color = C(5), name = 'Warmth'}; - -- warmth in measured in °C×10 + -- warmth in measured in d°C fatigue = {min = 0, max = 76 * 60, base = 0, desc = U('hr', 60, true), color = C(288,.3,.5), name = 'Fatigue'}; -- fatigue is measured in minutes one needs to sleep to cure it stamina = {min = 0, max = 20 * 100, base = true, desc = U('m', 100), color = C(88), name = 'Stamina'}; -- stamina is measured in how many 10th-nodes (== cm) one can sprint - hunger = {min = 0, max = 2000e3, base = 0, desc = U('kCal', 1000, true), color = C(43,.5,.4), name = 'Hunger'}; - -- hunger is measured in calories one must consume to cure it. at a 2kCal deficit, you start dying - thirst = {min = 0, max = 4e3, base = 0, desc = U('L', 1e3), color = C(217, .25,.4), name = 'Thirst'}; - -- thirst is measured in mL of H²O required to cure it + nutrition = {min = 0, max = 8000, base = 0, desc = U('kCal', 1, true), color = C(43,.5,.4), 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, .25,.4), name = 'Hydration', srzType = T.decimal}; + -- thirst is measured in L of H²O required to cure it morale = {min = 0, max = 24 * 60 * 10, base = true, desc = U('hr', 60, true), color = C(0,0,.8), name = 'Morale'}; -- morale is measured in minutes. e.g. at base rate morale degrades by -- 60 points every hour. morale can last up to 10 days - irradiation = {min = 0, max = 20000, base = 0, desc = U('Gy', 1000), color = C(141,1,.5), name = 'Irradiation'}; + irradiation = {min = 0, max = 10, base = 0, desc = U('Gy', 1), color = C(141,1,.5), name = 'Irradiation', 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 Index: mods/starlit/terrain.lua ================================================================== --- mods/starlit/terrain.lua +++ mods/starlit/terrain.lua @@ -6,11 +6,11 @@ footstep = 'default-dirt-footstep'; dig = 'default-dig-crumbly'; dug = 'default-dug-node'; } local sandSounds = { - footstep = 'default-sand-footstep'; + footstep = {name='default-sand-footstep',gain=0.1}; dig = 'default-dig-crumbly'; dug = 'default-dug-node'; } local grassSounds = { footstep = 'default-grass-footstep'; @@ -23,11 +23,10 @@ tiles = {'default_dirt.png'}; groups = {dirt = 1}; drop = ''; sounds = soilSounds; _starlit = { - onDestroy = function() end; kind = 'block'; elements = {}; }; }) Index: mods/starlit/user.lua ================================================================== --- mods/starlit/user.lua +++ mods/starlit/user.lua @@ -74,14 +74,12 @@ s.write('persona', self.persona) end; uiColor = function(self) return lib.color {hue=238,sat=.5,lum=.5} end; statDelta = function(self, stat, d, cause, abs) local dt = self.persona.statDeltas - local base + local min, max, base = self:statRange(stat) if abs then - local min, max - min, max, base = self:statRange(stat) if d == true then d = max elseif d == false then d = min end end if stat == 'health' then self.entity:set_hp(abs and d or (self.entity:get_hp() + d), cause) @@ -91,12 +89,17 @@ if abs then dt[stat] = d - base else dt[stat] = dt[stat] + d end + + if dt[stat]+base > max then dt[stat] = max-base + elseif dt[stat]+base < min then dt[stat] = min-base end self:pushPersona() end + + self:updateHUD() -- TODO trigger relevant animations? end; lookupSpecies = function(self) return starlit.world.species.lookup(self.persona.species, self.persona.speciesVariant) @@ -471,19 +474,20 @@ self:reconfigureSuit() -- i feel like there has to be a better way local cx = math.random(-500,500) - local startPoint + local iter, startPoint = 1 repeat local temp = -100 local cz = math.random(-500,500) local cy = minetest.get_spawn_level(cx, cz) if cy then startPoint = vector.new(cx,cy,cz) temp = starlit.world.climate.eval(startPoint,.5,.5).surfaceTemp end - if cx > 10000 then break end -- avoid infiniloop in pathological conditions + iter = iter + 1 + if iter > 100 then break end -- avoid infiniloop in pathological conditions until temp > -2 self.entity:set_pos(startPoint) meta:set_string('starlit_spawn', startPoint:to_string()) end; onDie = function(self, reason) @@ -498,15 +502,15 @@ end inv:set_list(lst, {}) end dropInv 'main' dropInv 'starlit_suit' - self:statDelta('psi', 0, 'death', true) - self:statDelta('hunger', 0, 'death', true) - self:statDelta('thirst', 0, 'death', true) - self:statDelta('fatigue', 0, 'death', true) - self:statDelta('stamina', 0, 'death', true) + self:statDelta('psi', 0, 'death', true) + self:statDelta('nutrition', 1500, 'death', true) + self:statDelta('hydration', 2, 'death', true) + self:statDelta('fatigue', 0, 'death', true) + self:statDelta('stamina', 0, 'death', true) self:updateSuit() end; onRespawn = function(self) local meta = self.entity:get_meta() self.entity:set_pos(vector.from_string(meta:get_string'starlit_spawn')) @@ -842,12 +846,26 @@ local dehydration = p:trait 'dehydration' * biointerval -- you dehydrate faster in higher temp dehydration = dehydration * math.max(1, starlit.world.climate.temp(u.entity:get_pos()) / 10) - u:statDelta('hunger', bmr) - u:statDelta('thirst', dehydration) + u:statDelta('nutrition', -bmr) + u:statDelta('hydration', -dehydration) + + if u:effectiveStat 'nutrition' == 0 then + -- starvation + end + + if u:effectiveStat 'hydration' == 0 then + -- dying of thirst + end + + local rads = u:effectiveStat 'irradiation' + if rads > 0 then + u:statDelta('irradiation', -0.0001 * biointerval) + end + end end) local cbit = { up = 0x001; Index: mods/starlit/world.lua ================================================================== --- mods/starlit/world.lua +++ mods/starlit/world.lua @@ -139,25 +139,23 @@ node.name = stageID(st.swap) minetest.swap_node(pos, node) return true end end - if st.biolum then - base.light_source = math.floor(st.biolum * (n/stageCt)) - end + if st.biolum then base.light_source = st.biolum; end return base end for i, v in ipairs(b.stages) do local n = regStage(i, v) - b.stageNodes[i] = n minetest.register_node(stageID(i), n) + b.stageNodes[i] = stageID(i) end b.fullyGrown = stageID(stageCt) local dec = { deco_type = 'simple'; - decoration = b.fullyGrown; + decoration = b.stageNodes; height = 1; param2 = b.meshOpt or 0; } for k,v in pairs(b.decoration) do dec[k] = v end b.decoration = minetest.register_decoration(dec) @@ -233,5 +231,29 @@ local dmg = math.ceil(dv * 2) user:statDelta('health', -dmg) end end end) + + +world.ecology.trees.foreach('starlit:tree-gen', {}, function(id, t) + local dec = { + deco_type = 'lsystem'; + treedef = t.def; + } + for k,v in pairs(t.decorate) do dec[k]=v end + minetest.register_decoration(dec) +end) + +minetest.register_abm { + label = "plant growth"; + nodenames = {'group:plant_grow'}; + chance = 15; + interval = 20; + catch_up = true; + action = function(pos, node) + local def = minetest.registered_nodes[node.name]._starlit.plant + local plant = starlit.world.ecology.plants.db[def.id] + local nextStage = plant.stageNodes[def.stage + 1] + minetest.swap_node(pos, {name=nextStage}) + end; +} Index: mods/vtlib/marshal.lua ================================================================== --- mods/vtlib/marshal.lua +++ mods/vtlib/marshal.lua @@ -136,27 +136,29 @@ function G.int(bits,signed) local bytes = math.ceil(bits / 8) local max = 2 ^ bits local spoint = math.floor(max/2) - return { - sz = bytes; - name = string.format("%sint<%s>", + local name = string.format("%sint<%s>", signed and 's' or 'u', bits ); + return { + name = name; + sz = bytes; enc = function(obj) + report('encoding %s value=%s', name, dump(obj)) obj = obj or 0 local val = math.abs(obj) local str = '' if signed then local max = math.floor(max / 2) if (obj > max) or (obj < (0-(max+1))) then - return m.err.domain end + return error('domain error') end if obj < 0 then val = val + spoint end -- e.g. for 8bit: 0x80 == -1; 0xFF = -128 else - if val > max then return m.err.domain end + if val > max then error('domain error') end end for i=1,bytes do local n = math.fmod(val, 0x100) str = str .. string.char(n) val = math.floor(val / 0x100) @@ -200,10 +202,11 @@ name = 'struct' .. (name and ':' .. name or ''); report('defining struct name=%q fields=%s', name, dump(def)) return { name = name; enc = function(obj) + report('encoding struct name=%q vals=%s', name, dump(obj)) local enc = m.streamEncoder() local n = 0 for k,ty in pairs(def) do n=n+1 if obj[k] == nil then error('missing key '..dump(k)..' for type '..ty.name) end local encoded = ty.enc(obj[k]) Index: mods/vtlib/ui.lua ================================================================== --- mods/vtlib/ui.lua +++ mods/vtlib/ui.lua @@ -44,11 +44,11 @@ tooltipper = function(dui) -- takes a configuration table mapping affinities to colors. -- 'neutral' is the only required affinity return function(a) local color = a.color and a.color:readable(0.65, 1.0) - if color == nil then color = l.color(136,158,177) end + if color == nil then color = l.color(.5,.5,.5) end local str = a.title if a.desc then str = str .. '\n' .. color:fmt(minetest.wrap_text(a.desc,60)) end if a.props then