Comment: | check in missing mod, add forest biome, racial powers, overlays (untested) |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
6deb9bedbcb3cc5a6bba5e548bd6f499 |
User & Date: | lexi on 2024-05-02 20:27:05 |
Other Links: | manifest | tags |
2024-05-03
| ||
00:10 | add sprint, improve bio job, rebalance stamina regen, various fixes check-in: cade6683f7 user: lexi tags: trunk | |
2024-05-02
| ||
20:27 | check in missing mod, add forest biome, racial powers, overlays (untested) check-in: 6deb9bedbc user: lexi tags: trunk | |
00:22 | plant growth, edibles, fixes check-in: e829ca194a user: lexi tags: trunk | |
Added mods/starlit-eco/init.lua version [ffe9d8ff5f].
1 +local world = starlit.world 2 +local lib = starlit.mod.lib 3 + 4 +world.ecology.biomes.link('starlit:steppe', { 5 + nightTempDelta = -30; 6 + waterTempDelta = 0; 7 + -- W Sp Su Au W 8 + seasonalTemp = {-50, -10, 5, 5, -20, -50}; 9 + def = { 10 + node_top = 'starlit:greengraze', depth_top = 1; 11 + node_filler = 'starlit:soil', depth_filler = 4; 12 + node_riverbed = 'starlit:sand', depth_riverbed = 4; 13 + y_min = 0; 14 + y_max = 512; 15 + heat_point = 10; 16 + humidity_point = 30; 17 + }; 18 +}) 19 + 20 +world.ecology.biomes.link('starlit:forest', { 21 + nightTempDelta = -20; 22 + waterTempDelta = 0; 23 + -- W Sp Su Au W 24 + seasonalTemp = {-40, -8, 10, 10, -14, -40}; 25 + def = { 26 + node_top = 'starlit:greengraze', depth_top = 1; 27 + node_filler = 'starlit:soil', depth_filler = 4; 28 + node_riverbed = 'starlit:sand', depth_riverbed = 4; 29 + y_min = -100; 30 + y_max = 256; 31 + heat_point = 13; 32 + humidity_point = 40; 33 + }; 34 +}) 35 + 36 +world.ecology.biomes.link('starlit:desert', { 37 + nightTempDelta = -40; 38 + waterTempDelta = 0; 39 + -- W Sp Su Au W 40 + seasonalTemp = {-10, -5, 15, 15, -5, -10}; 41 + def = { 42 + node_top = 'starlit:sand', depth_top = 1; 43 + node_filler = 'starlit:sand', depth_filler = 4; 44 + node_riverbed = 'starlit:sand', depth_riverbed = 4; 45 + y_min = 0; 46 + y_max = 512; 47 + heat_point = 20; 48 + humidity_point = 10; 49 + }; 50 +}) 51 + 52 +world.ecology.biomes.link('starlit:ocean', { 53 + nightTempDelta = -35; 54 + waterTempDelta = 5; 55 + seasonalTemp = {0}; -- no seasonal variance 56 + def = { 57 + y_max = 3; 58 + y_min = -512; 59 + heat_point = 15; 60 + humidity_point = 50; 61 + node_top = 'starlit:sand', depth_top = 1; 62 + node_filler = 'starlit:sand', depth_filler = 3; 63 + }; 64 +}) 65 + 66 +minetest.register_craftitem('starlit_eco:fiber', { 67 + description = "Plant Fiber"; 68 + groups = {fiber = 1}; 69 + inventory_image = lib.image('starlit-eco-plant-fiber.png'):shift(lib.color(0,1,0)):render(); 70 + _starlit = { 71 + recover_vary = function(rng, ctx) 72 + return starlit.type.fab { 73 + element = { carbon = rng:int(0,1) }; 74 + }; 75 + end; 76 + }; 77 +}) 78 + 79 +starlit.include 'plants' 80 +starlit.include 'trees'
Added mods/starlit-eco/mod.conf version [148d1a5e9a].
1 +name = starlit_eco 2 +title = starlit ecosphere 3 +description = plants and biomes 4 +depends = starlit
Added mods/starlit-eco/plants.lua version [e9756bfa75].
1 +local world = starlit.world 2 +local lib = starlit.mod.lib 3 + 4 +local function dropCat(a,b) 5 + local function strdrop(s) 6 + if type(s) == 'string' then 7 + return {max_items = 1; items = {{items={s}}}} 8 + else return s end 9 + end 10 + a = strdrop(a) 11 + b = strdrop(b) 12 + return { 13 + max_items = a.max_items + b.max_items; 14 + items = lib.tbl.append(a.items, b.items); 15 + } 16 +end 17 +local function stalkPlant(def) 18 + local function stage(s, drops, swap) 19 + return { 20 + tex = lib.image(string.format('starlit-eco-plant-stalk%s.png',s)):shift(def.color); 21 + drop = drops; 22 + swap = swap; 23 + } 24 + end 25 + local function plantMatter(opts) 26 + local dps = { 27 + seed = def.seed; 28 + fiber = def.fiber; 29 + leaf = def.leaf and def.leaf.drop or nil; 30 + berry = def.berries and def.berries.drop or nil; 31 + } 32 + local t = {max_items=0, items={}} 33 + for k,v in pairs(opts) do 34 + if dps[v] then t = dropCat(dps[v], t) end 35 + end 36 + return t 37 + end 38 + 39 + local fg 40 + local stages = { 41 + stage('-grow-1', ''); 42 + stage('-grow-2', plantMatter{'seed'}); 43 + stage('-grow-3', plantMatter{'seed','fiber'}); 44 + stage('', plantMatter{'seed','seed','fiber'}); 45 + }; 46 + if def.leaf then 47 + local ps = stage('', plantMatter{'seed','seed','seed','fiber','leaf'}) 48 + ps.tex = ps.tex .. lib.image('starlit-eco-plant-stalk-petals.png'):shift(def.leaf.color) 49 + table.insert(stages, ps) 50 + end 51 + if def.berries then 52 + local ps = lib.image.clone(stages[#stages]) 53 + ps.tex = ps.tex:blit(lib.image('starlit-eco-plant-stalk-berries.png'):shift(def.berries.color)) 54 + ps.drop = def.berries.drop; 55 + ps.swap = #stages 56 + table.insert(stages, ps) 57 + end 58 + 59 + if def.biolum then for i,v in ipairs(stages) do 60 + v.biolum = math.floor(def.biolum * (i/#stages)) 61 + end end 62 + 63 + world.ecology.plants.link(def.id, { 64 + name = def.name; 65 + stages = stages; 66 + decoration = def.decoration; 67 + meshOpt = 3; 68 + }) 69 +end 70 + 71 +local function simpleDrop(rarity, what) 72 + return { 73 + max_items = 1; 74 + items = { 75 + {rarity = rarity, items = {what}}; 76 + }; 77 + }; 78 +end 79 + 80 +function stalkPlantAuto(def) 81 + local id = def.id 82 + local id_berries = def.id .. '_berry' 83 + local id_seed = def.id .. '_seed' 84 + 85 + local p = lib.tbl.proto({}, def) 86 + if def.berries then 87 + local bdef = lib.tbl.defaults({ 88 + name = def.name .. ' Berry'; 89 + tex = lib.image('starlit-eco-plant-berry-bunch.png'):shift(def.berries.color or def.color):render(); 90 + color = def.color; 91 + }, def.berries) 92 + bdef.name = bdef.name 93 + starlit.item.food.link(id_berries, bdef) 94 + p.berries = { 95 + color = def.berries.color; 96 + drop = id_berries; 97 + } 98 + end 99 + 100 + if def.seed then 101 + local sdef = lib.tbl.defaults({ 102 + name = def.name .. ' Seed'; 103 + tex = lib.image('starlit-eco-plant-seeds.png'):shift(def.seed.color or def.color):render(); 104 + color = def.color; 105 + grow = {kind = 'plant', id = id}; 106 + }, def.seed) 107 + 108 + starlit.item.seed.link(id_seed, sdef) 109 + p.seed = id_seed 110 + end 111 + 112 + return stalkPlant(p) 113 +end 114 + 115 +stalkPlantAuto { 116 + id = 'starlit_eco:moondrop'; 117 + name = "Moondrop"; 118 + fiber = simpleDrop(2, 'starlit_eco:fiber'); 119 + seed = {}; 120 + color = lib.color(.5, .7, 1); 121 + biolum = 5; 122 + leaf = { 123 + color = lib.color(.6, .8, .8); 124 + drop = simpleDrop(2, 'starlit_eco:moondrop_petal'); 125 + }; 126 + berries = { 127 + desc = "The fruits of the moondrop are not very nutritious, but their peculiar sweet-sour flavor profile makes them one Thousand Petal's great delicacies"; 128 + color = lib.color(1,0,.4); 129 + nourish = 10; 130 + hydrate = 0.05; 131 + taste = 1 * 60; 132 + mass = 1; 133 + }; 134 + decoration = { 135 + place_on = 'starlit:greengraze'; 136 + fill_ratio = 0.03; 137 + biomes = {'starlit:steppe', 'starlit:forest'}; 138 + y_min = 10; 139 + y_max = 100; 140 + }; 141 +} 142 + 143 +stalkPlantAuto { 144 + id = 'starlit_eco:dustrose'; 145 + name = "Dust Rose"; 146 + fiber = simpleDrop(2, 'starlit_eco:fiber'); 147 + seed = {}; 148 + color = lib.color(.3, .1, .2); 149 + leaf = { 150 + color = lib.color(.7, .4, .8); 151 + drop = simpleDrop(2, 'starlit_eco:dustrose_petal'); 152 + }; 153 + decoration = { 154 + place_on = 'starlit:greengraze'; 155 + fill_ratio = 0.03; 156 + biomes = {'starlit:forest'}; 157 + y_min = -50; 158 + y_max = 50; 159 + }; 160 +} 161 + 162 +stalkPlantAuto { 163 + id = 'starlit_eco:harrowstalk'; 164 + name = "Harrowstalk"; 165 + fiber = simpleDrop(2, 'starlit_eco:fiber'); 166 + seed = {}; 167 + color = lib.color(.3, .2, .1); 168 + decoration = { 169 + place_on = 'starlit:sand'; 170 + fill_ratio = 0.03; 171 + biomes = {'starlit:ocean', 'starlit:desert'}; 172 + y_min = -30; 173 + y_max = 400; 174 + }; 175 +}
Added mods/starlit-eco/trees.lua version [49c5f4ea72].
1 +local world = starlit.world 2 +local lib = starlit.mod.lib 3 + 4 +local function woodProps(def) return { 5 + recover = starlit.type.fab { 6 + time = { shred = 2; }; 7 + cost = { shredPower = 1.5; }; 8 + }; 9 + recover_vary = function(rng, ctx) 10 + return starlit.type.fab { 11 + element = { 12 + potassium = rng:int(0,1); 13 + carbon = rng:int(0,2); 14 + } 15 + }; 16 + end; 17 + mass = 1.5e3; 18 +} end 19 + 20 +local function leafProps(def) return { 21 + recover = starlit.type.fab { 22 + time = { shred = .5; }; 23 + cost = { shredPower = .3; }; 24 + }; 25 + recover_vary = function(rng, ctx) 26 + return starlit.type.fab { 27 + element = { 28 + potassium = rng:int(0,2); 29 + carbon = rng:int(0,1); 30 + } 31 + }; 32 + end; 33 + mass = 100; 34 +} end 35 + 36 +local function regLog(id, def) 37 + local base = table.copy(def) 38 + base.groups = base.groups or {} 39 + base.groups.wood = 1 40 + base.groups.log = 1 41 + base.groups.falling_node = 1 42 + 43 + local live = table.copy(base) 44 + live.drop = id 45 + live.groups.alive = 1 46 + minetest.register_node(id, base) 47 + minetest.register_node(id..'_live', live) 48 +end 49 + 50 +regLog('starlit_eco:lambent_pine_log', { 51 + description = 'Lambent Pine Log'; 52 + drawtype = 'normal'; 53 + tiles = { 54 + 'starlit-eco-tree-lambent-pine-trunk-top.png'; 55 + 'starlit-eco-tree-lambent-pine-trunk.png'; 56 + }; 57 + _starlit = woodProps{}; 58 +}) 59 + 60 + 61 +starlit.item.food.link('starlit_eco:lambent_pine_berry', { 62 + name = 'Lambent Pine Berry'; 63 + desc = 'Though packed with human-compatible nutrients, these berries are almost painfully sour when eaten raw.'; 64 + tex = lib.image('starlit-eco-plant-berry-bunch.png'):shift{hue=180,sat=-30,lum=30}:render(); 65 + nourish = 150; 66 + taste = -2 * 60; 67 + mass = 2; 68 +}) 69 + 70 +starlit.item.seed.link('starlit_eco:lambent_pine_seed', { 71 + name = 'Lambent Pine Seed'; 72 + tex = lib.image('starlit-eco-plant-seeds.png'):shift{hue=150, sat=-50, lum=80}:render(); 73 + grow = {kind = 'tree', id = 'starlit_eco:lambent_pine'}; 74 +}) 75 + 76 +minetest.register_node('starlit_eco:lambent_pine_bulb', { 77 + description = 'Lambent Pine Bulb'; 78 + drawtype = 'nodebox'; 79 + connects_to = {'starlit_eco:lambent_pine_needles'}; 80 + node_box = { 81 + type = 'connected'; 82 + connect_top = { 83 + {-.1, .5, -.1, 84 + .1, .3, .1}; 85 + }; 86 + fixed = { 87 + {-.2, -.2, -.2, 88 + .2, .3, .2}; 89 + }; 90 + }; 91 + light_source = 6; 92 + drop = { 93 + max_items = 3; 94 + items = { 95 + {rarity = 4, items = {'starlit_eco:lambent_pine_seed'}}; 96 + {rarity = 3, items = {'starlit_eco:lambent_pine_berry'}}; 97 + {rarity = 2, items = {'starlit_eco:lambent_pine_berry'}}; 98 + {items = {'starlit_eco:lambent_pine_berry'}}; 99 + }; 100 + }; 101 + groups = {plant=1, attached_node = 4}; 102 + tiles = { 103 + 'starlit-eco-tree-lambent-pine-bulb.png'; 104 + }; 105 + _starlit = woodProps{}; 106 +}) 107 + 108 +minetest.register_node('starlit_eco:lambent_pine_needles', { 109 + description = 'Lambent Pine Needles'; 110 + groups = {plant = 1;}; 111 + drop = ''; 112 + tiles = { 113 + 'starlit-eco-tree-lambent-pine-needles.png'; 114 + 'starlit-eco-tree-lambent-pine-needles.png'; 115 + }; 116 + _starlit = leafProps{}; 117 +}); 118 + 119 +regLog('starlit_eco:starblossom_log', { 120 + description = 'Starblossom Log'; 121 + drawtype = 'normal'; 122 + tiles = { 123 + 'starlit-eco-tree-starblossom-trunk-top.png'; 124 + 'starlit-eco-tree-starblossom-trunk.png'; 125 + }; 126 + _starlit = woodProps{}; 127 +}) 128 + 129 +minetest.register_node('starlit_eco:starblossom_leaves', { 130 + description = 'Starblossom Leaves'; 131 + groups = {plant = 1;}; 132 + drop = ''; 133 + tiles = { 134 + 'starlit-eco-tree-starblossom-leaves.png'; 135 + 'starlit-eco-tree-starblossom-leaves.png'; 136 + }; 137 + _starlit = leafProps{}; 138 +}); 139 +minetest.register_node('starlit_eco:starblossom_leaves_shine', { 140 + description = 'Shining Starblossom Leaves'; 141 + groups = {plant = 1;}; 142 + drop = ''; 143 + paramtype = 'light'; 144 + light_source = 4; 145 + tiles = { 146 + 'starlit-eco-tree-starblossom-leaves.png'; 147 + 'starlit-eco-tree-starblossom-leaves.png'; 148 + 'starlit-eco-tree-starblossom-leaves.png^starlit-eco-tree-starblossom-shine.png'; 149 + }; 150 + _starlit = leafProps{}; 151 +}); 152 + 153 +starlit.world.ecology.trees.meld { 154 + ['starlit_eco:lambent_pine'] = { 155 + name = 'Lambent Pine'; 156 + def = { 157 + axiom = 'TTB'; 158 + rules_a = '[-[&Tf]Tf][+[^Tf]Tf]f'; 159 + rules_c = '[-[&Tff]Tff][+[^Tff]Tff]f'; 160 + rules_b = 'TCA[f]B'; 161 + 162 + -- nodes 163 + trunk = 'starlit_eco:lambent_pine_log_live'; 164 + leaves = 'starlit_eco:lambent_pine_needles'; 165 + 166 + angle = 90; 167 + 168 + iterations = 7; 169 + random_level = 3; 170 + trunk_type = 'single'; 171 + thin_branches = true; 172 + 173 + fruit = 'starlit_eco:lambent_pine_bulb'; 174 + fruit_chance = 0; 175 + }; 176 + decorate = { 177 + { biomes = {'starlit:forest'}; 178 + place_on = 'starlit:greengraze'; 179 + fill_ratio = 0.004; 180 + y_min = -30, y_max = 500; 181 + seed = 0xe8190e; 182 + }; 183 + { biomes = {'starlit:steppe'}; 184 + place_on = 'starlit:greengraze'; 185 + fill_ratio = 0.002; 186 + y_min = -30, y_max = 500; 187 + seed = 0xe8190e; 188 + }; 189 + }; 190 + }; 191 + 192 + ['starlit_eco:starblossom'] = { 193 + def = { 194 + axiom = 'TTTTATTTT[&&B]' .. string.rep(string.rep('/', 4) .. '[&&B]', math.floor(360/40)); 195 + rules_a = 'TTTa'; 196 + rules_b = 'FF&B'; 197 + 198 + trunk_type = 'double'; 199 + trunk = 'starlit_eco:starblossom_log_live'; 200 + leaves = 'starlit_eco:starblossom_leaves'; 201 + leaves2 = 'starlit_eco:starblossom_leaves_shine'; 202 + leaves2_chance = 20; 203 + 204 + angle = 10; 205 + iterations = 13; 206 + random_level = 5; 207 + }; 208 + decorate = { 209 + { biomes = {'starlit:forest'}; 210 + place_on = 'starlit:greengraze'; 211 + fill_ratio = 0.001; 212 + y_min = -20, y_max = 512; 213 + }; 214 + }; 215 + }; 216 +} 217 + 218 +minetest.register_abm { 219 + label = "lambent pine fruiting"; 220 + nodenames = {'starlit_eco:lambent_pine_needles'}; 221 + neighbors = {'starlit_eco:lambent_pine_log_live'}; 222 + chance = 40; 223 + interval = 80; 224 + catch_up = true; 225 + action = function(pos, node) 226 + local po = pos:offset(0,-1,0) 227 + if minetest.get_node(po).name == "air" then 228 + minetest.add_node(po, {name='starlit_eco:lambent_pine_bulb'}) 229 + end 230 + end; 231 +}
Modified mods/starlit-electronics/init.lua from [67a7c4791a] to [c28c8fe2b6].
518 518 ----------- 519 519 -- chips -- 520 520 ----------- 521 521 522 522 E.sw = {} 523 523 function E.sw.findSchematicFor(item) 524 524 local id = ItemStack(item):get_name() 525 - print(id) 526 525 local fm = minetest.registered_items[id]._starlit 527 526 if not (fm and fm.fab and fm.fab.reverseEngineer) then return nil end 528 527 local id = fm.fab.reverseEngineer.sw 529 528 return id, starlit.item.sw.db[id] 530 529 end 531 530 532 531 E.chip = { file = {} }
Modified mods/starlit/init.lua from [e52f2bba90] to [435c654ad9].
348 348 349 349 local function pointChanged(a,b) 350 350 return a.type ~= b.type 351 351 or a.type == 'node' and vector.new(a.under) ~= vector.new(b.under) 352 352 or a.type == 'object' and a.ref ~= b.ref 353 353 end 354 354 local function triggerPower(_, luser, point) 355 - for k,v in pairs(starlit.activeUsers) do 356 - print (k,v) end 357 - print("trigger", luser, luser:get_player_name()) 355 +-- print("trigger", luser, luser:get_player_name()) 358 356 local user = starlit.activeUsers[luser:get_player_name()] 359 357 local oldTgt = user.action.tgt 360 358 user.action.tgt = point 361 359 if bit.band(user.action.bits, 0x100)==0 then 362 360 user.action.bits = bit.bor(user.action.bits, 0x100) 363 361 --return user:trigger('secondary', {state = 'prog', delta = 0}) 364 362 elseif pointChanged(oldTgt, point) then ................................................................................ 388 386 minetest.register_item("starlit:_hand_dig", { 389 387 type = "none", 390 388 wield_image = "wieldhand.png", 391 389 wield_scale = {x=1,y=1,z=2.5}, 392 390 tool_capabilities = { 393 391 groupcaps = { 394 392 plant = {maxlevel=1, times = {.50}}; 395 - dirt = {maxlevel=1, times = {2.5}}; 396 393 397 - log = {maxlevel=1, times = {1}}; 394 + -- sand, dirt, gravel 395 + looseClump = {maxlevel=1, times = {1.5, 2.5}}; 398 396 }; 399 397 } 400 398 }) 401 399 402 400 minetest.register_on_player_inventory_action(function(luser, act, inv, p) 403 401 local name = luser:get_player_name() 404 402 local user = starlit.activeUsers[name] ................................................................................ 429 427 return vector.new( 430 428 r(pos.x), 431 429 r(pos.y), 432 430 r(pos.z) 433 431 ) 434 432 end 435 433 for i, it in ipairs(drops) do 436 - local it = minetest.add_item(jitter(pos), it) 437 - local dp = vector.new(0,0,0) 438 - if digger then dp = digger:get_pos() end 439 - local delta = dp - it:get_pos() 440 - it:add_velocity(vector.new(delta.x,0,delta.z)); 434 + if type(it) == 'string' then it = ItemStack(it) end 435 + if not it:is_empty() then 436 + local ent = minetest.add_item(jitter(pos), it) 437 + if ent ~= nil then -- avoid crash when dropping unknown item 438 + local dp = vector.new(0,0,0) 439 + if digger then dp = digger:get_pos() end 440 + local delta = dp - ent:get_pos() 441 + ent:add_velocity(vector.new(delta.x,0,delta.z)); 442 + end 443 + end 441 444 end 442 445 end 443 446 444 447 445 448 -- TODO timer iterates live UI 446 449
Modified mods/starlit/interfaces.lua from [497adf50ee] to [db0300e682].
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 - return a.chipID == b.chipID and a.pgmIndex == b.pgmIndex 133 + return (a.chipID ~= nil and (a.chipID == b.chipID and a.pgmIndex == b.pgmIndex)) 134 + or (a.ref ~= nil and a.ref == b.ref) 134 135 end 135 136 136 137 starlit.interface.install(starlit.type.ui { 137 138 id = 'starlit:user-menu'; 138 139 pages = { 139 140 compiler = { 140 141 setupState = function(state, user) ................................................................................ 357 358 local st = string.format('%s / %s', s.desc(amt, true), s.desc(max)) 358 359 table.insert(tb, {kind = 'hztl', padding = 0.25; 359 360 {kind = 'label', w=2, h=barh, text = s.name}; 360 361 {kind = 'hbar', w=4, h=barh, fac = sv, text = st, color=s.color}; 361 362 }) 362 363 end 363 364 local abilities = { 364 - {id = 'abl_sprint', label = 'Sprint', img = 'starlit-ui-icon-ability-sprint.png'}; 365 + maneuver = {}; 366 + direct = {}; 367 + passive = {}; 365 368 } 366 - table.insert(tb, wrapMenu(6.25,4, 1,2, abilities)) 369 + state.abilityMap = {} 370 + for i, a in pairs(user:species().abilities) do 371 + local id = 'abl_'..a.id; 372 + state.abilityMap[id] = a; 373 + table.insert(abilities[a.powerKind], { 374 + id = id; 375 + label = a.name; 376 + desc = a.desc; 377 + img = a.img; 378 + 379 + -- HACK 380 + color = pptrMatch(user.power.maneuver, {ref=a}) and 381 + {hue = 150, sat = 0, lum = .3} or nil; 382 + }); 383 + end 384 + for i, n in ipairs {'maneuver', 'direct', 'passive'} do 385 + if next(abilities[n]) then 386 + table.insert(tb, wrapMenu(6.25,4, 1,2, abilities[n])) 387 + end 388 + end 367 389 return starlit.ui.build(tb) 390 + end; 391 + handle = function(state, user, q) 392 + for k,a in pairs(state.abilityMap) do 393 + if q[k] then 394 + if a.powerKind == 'maneuver' then 395 + if pptrMatch(user.power.maneuver, {ref=a}) then 396 + user.power.maneuver = nil 397 + else 398 + user.power.maneuver = {ref=a} 399 + end 400 + user:suitSound 'starlit-configure' 401 + return true 402 + elseif a.powerKind == 'direct' then 403 + elseif a.powerKind == 'passive' then 404 + else error('bad ability kind ' .. a.powerKind) end 405 + break 406 + end 407 + end 368 408 end; 369 409 }; 370 410 suit = { 371 411 render = function(state, user) 372 412 local suit = user:getSuit() 373 413 local suitDef = suit:def() 374 414 local chipW, chipH = listWrap(suitDef.slots.chips, 5)
Modified mods/starlit/species.lua from [b30e9eb59a] to [1469667980].
10 10 str = T.str; 11 11 num = T.decimal; 12 12 } 13 13 end 14 14 15 15 -- constants 16 16 local animationFrameRate = 60 17 + 18 +local bioAbilities = { 19 + sprint = { 20 + id = 'sprint'; 21 + name = 'Sprint'; 22 + desc = 'Put on a short burst of speed at the cost of some stamina'; 23 + img = 'starlit-ui-icon-ability-sprint.png'; 24 + powerKind = 'maneuver'; 25 + run = function(user, ctx) 26 + end; 27 + }; 28 +} 17 29 18 30 local species = { 19 31 human = { 20 32 name = 'Human'; 21 33 desc = 'The weeds of the galactic flowerbed. Humans are one of the Lesser Races, excluded from the ranks of the Starlit by souls that lack, in normal circumstances, external psionic channels. Their mastery of the universe cut unexpectedly short, forever locked out of FTL travel, short-lived without augments, and alternately pitied or scorned by the lowest of the low, humans flourish nonetheless due to a capacity for adaptation unmatched among the Thinking Few, terrifyingly rapid reproductive cycles -- and a keen facility for bribery. While the lack of human psions remains a sensitive topic, humans (unlike the bitter and emotional Kruthandi) are practical enough to hire the talent they cannot possess, and have even built a small number of symbiotic civilizations with the more indulging of the Powers. In a galaxy where nearly all sophont life is specialized to a fault, humans have found the unique niche of occupying no particular niche.'; 22 34 scale = 1.0; 23 35 params = { ................................................................................ 58 70 health = 400; 59 71 lungCapacity = .6; 60 72 irradiation = 0.8; -- you are smaller, so it takes less rads to kill ya 61 73 sturdiness = 0; -- women are more fragile and thus susceptible to blunt force trauma 62 74 metabolism = .150; -- kCal/s 63 75 painTolerance = 0.4; 64 76 dehydration = 10e-4; -- L/s 77 + speed = 1.1; 65 78 }; 66 79 }; 67 80 male = { 68 81 name = 'Human Male'; 69 82 eyeHeight = 1.6; 70 83 stats = { 71 84 psiRegen = 1.0; ................................................................................ 78 91 traits = { 79 92 health = 500; 80 93 painTolerance = 1.0; 81 94 lungCapacity = 1.0; 82 95 sturdiness = 0.3; 83 96 metabolism = .150; -- kCal/s 84 97 dehydration = 15e-4; -- L/s 98 + speed = 1.0; 85 99 }; 86 100 }; 87 101 }; 88 102 traits = {}; 103 + abilities = {bioAbilities.sprint}; 89 104 }; 90 105 } 91 106 92 107 93 108 starlit.world.species = { 94 109 index = species; 95 110 paramTypes = paramTypes;
Modified mods/starlit/stats.lua from [c485cf1b8a] to [93739694fe].
22 22 return lib.color {hue = h, sat = s or 1, lum = l or .7} 23 23 end 24 24 starlit.world.stats = { 25 25 psi = {min = 0, max = 500, base = 0, desc = U('ψ', 10), color = C(320), name = 'Numina'}; 26 26 -- numina is measured in daψ 27 27 warmth = {min = -1000, max = 1000, base = 0, desc = U('°C', 10, true), color = C(5), name = 'Warmth'}; 28 28 -- warmth in measured in d°C 29 - fatigue = {min = 0, max = 76 * 60, base = 0, desc = U('hr', 60, true), color = C(288,.3,.5), name = 'Fatigue'}; 29 + fatigue = {min = 0, max = 76 * 60, base = 0, desc = U('hr', 60, true), color = C(288,.3,.5), name = 'Fatigue', srzType = T.decimal}; 30 30 -- fatigue is measured in minutes one needs to sleep to cure it 31 31 stamina = {min = 0, max = 20 * 100, base = true, desc = U('m', 100), color = C(88), name = 'Stamina'}; 32 32 -- stamina is measured in how many 10th-nodes (== cm) one can sprint 33 33 nutrition = {min = 0, max = 8000, base = 0, desc = U('kCal', 1, true), color = C(43,.5,.4), name = 'Nutrition', srzType = T.decimal}; 34 34 -- hunger is measured in kcalories one must consume to cure it. at 0, you start dying 35 35 hydration = {min = 0, max = 4, base = 0, desc = U('L', 1), color = C(217, .25,.4), name = 'Hydration', srzType = T.decimal}; 36 36 -- thirst is measured in L of H²O required to cure it 37 - morale = {min = 0, max = 24 * 60 * 10, base = true, desc = U('hr', 60, true), color = C(0,0,.8), name = 'Morale'}; 37 + morale = {min = 0, max = 10 * 24 * 60, base = true, desc = U('hr', 60, true), color = C(0,0,.8), name = 'Morale', srzType = T.decimal}; 38 38 -- morale is measured in minutes. e.g. at base rate morale degrades by 39 - -- 60 points every hour. morale can last up to 10 days 39 + -- 60 points every hour. morale can last up to 10 earthdays 40 40 irradiation = {min = 0, max = 10, base = 0, desc = U('Gy', 1), color = C(141,1,.5), name = 'Irradiation', srzType = T.decimal}; 41 41 -- irrad is measured is milligreys 42 42 -- 1Gy counters natural healing 43 43 -- ~3Gy counters basic nanomedicine 44 44 -- 5Gy causes death within two weeks without nanomedicine 45 45 -- radiation speeds up psi regen 46 46 -- morale drain doubles with each 2Gy 47 - illness = {min = 0, max = 1000, base = 0, desc = U('%', 10, true), color = C(71,.4,.25), name = 'Illness'}; 47 + illness = {min = 0, max = 1, base = 0, desc = U('%', .01, true), color = C(71,.4,.25), name = 'Illness', srzType = T.factor}; 48 48 -- as illness increases, maximum stamina and health gain a corresponding limit 49 49 -- illness is increased by certain conditions, and decreases on its own as your 50 50 -- body heals when those conditions wear off. some drugs can lower accumulated illness 51 51 -- but illness-causing conditions require specific cures 52 52 -- illness also causes thirst and fatigue to increase proportionately 53 53 }
Modified mods/starlit/terrain.lua from [033036f747] to [43f9137bd9].
1 1 local T = starlit.translator 2 2 local lib = starlit.mod.lib 3 3 4 4 starlit.terrain = {} 5 5 local soilSounds = { 6 6 footstep = 'default-dirt-footstep'; 7 - dig = 'default-dig-crumbly'; 8 7 dug = 'default-dug-node'; 9 8 } 10 9 local sandSounds = { 11 10 footstep = {name='default-sand-footstep',gain=0.1}; 12 - dig = 'default-dig-crumbly'; 13 11 dug = 'default-dug-node'; 14 12 } 15 13 local grassSounds = { 16 14 footstep = 'default-grass-footstep'; 17 - dig = 'default-dig-crumbly'; 15 + dug = 'default-dug-node'; 16 +} 17 +local hardSounds = { 18 + footstep = 'default-hard-footstep'; 18 19 dug = 'default-dug-node'; 19 20 } 20 21 22 +local soilDrop = { 23 + max_items = 3; 24 + items = { 25 + {rarity = 2, items = {'starlit:soil_clump'}}; 26 + {rarity = 3, items = {'starlit:soil_clump'}}; 27 + {rarity = 4, items = {'starlit:soil_clump'}}; 28 + }; 29 +} 21 30 minetest.register_node('starlit:soil', { 22 31 description = T 'Soil'; 23 - tiles = {'default_dirt.png'}; 24 - groups = {dirt = 1}; 25 - drop = ''; 32 + tiles = {'starlit-terrain-soil.png'}; 33 + groups = {looseClump = 2, soil = 1}; 34 + drop = soilDrop; 26 35 sounds = soilSounds; 27 36 _starlit = { 28 37 kind = 'block'; 29 38 elements = {}; 30 39 }; 31 40 }) 32 41 33 42 34 43 minetest.register_node('starlit:sand', { 35 44 description = T 'Sand'; 36 - tiles = {'default_sand.png'}; 37 - groups = {dirt = 1}; 45 + tiles = {'starlit-terrain-sand.png'}; 46 + groups = {looseClump = 1, sand = 1}; 38 47 drop = ''; 39 48 sounds = sandSounds; 40 49 _starlit = { 41 50 kind = 'block'; 42 51 fab = starlit.type.fab { element = { silicon = 25 } }; 43 52 }; 44 53 }) ................................................................................ 46 55 short_description = T 'Soil'; 47 56 description = starlit.ui.tooltip { 48 57 title = T 'Soil'; 49 58 desc = 'A handful of nutrient-packed soil, suitable for growing plants'; 50 59 color = lib.color(0.3,0.2,0.1); 51 60 }; 52 61 inventory_image = 'starlit-item-soil.png'; 53 - groups = {soil = 1}; 62 + groups = {looseClump = 2, soil = 1}; 63 + on_place = function(me, luser, point) 64 + if me:get_count() < 3 then return end 65 + if minetest.place_node(point.above, {name = 'starlit:soil'}, luser) then 66 + me:take_item(3) 67 + end 68 + return me 69 + end; 54 70 _starlit = { 55 71 fab = starlit.type.fab { element = { carbon = 12 / 4 } }; 56 72 }; 57 73 }) 58 74 59 75 function starlit.terrain.createGrass(def) 60 76 local drop = { ................................................................................ 66 82 }; 67 83 }; 68 84 } 69 85 minetest.register_node(def.name, { 70 86 description = T 'Greengraze'; 71 87 tiles = { 72 88 def.img .. '.png'; 73 - 'default_dirt.png'; 89 + 'starlit-terrain-soil.png'; 74 90 { 75 - name = 'default_dirt.png^' .. def.img ..'_side.png'; 91 + name = 'starlit-terrain-soil.png^' .. def.img ..'-overlay.png'; 76 92 tileable_vertical = false; 77 93 }; 78 94 }; 79 - groups = {grass = 1, dirt = 1, sub_walk = 1}; 80 - drop = ''; 95 + groups = {looseClump = 2, grass = 1, soil = 1, sub_walk = 1}; 96 + drop = soilDrop; 81 97 sounds = grassSounds; 82 98 _starlit = { 83 99 fab = def.fab; 84 100 recover = def.recover; 85 101 recover_vary = def.recover_vary; 86 102 }; 87 103 }) 88 104 end 89 105 90 106 91 107 starlit.terrain.createGrass { 92 108 name = 'starlit:greengraze'; 93 109 desc = T 'Greengraze'; 94 - img = 'default_grass'; 110 + img = 'starlit-terrain-greengraze'; 95 111 fab = starlit.type.fab { 96 112 element = { 97 113 carbon = 12; 98 114 }; 99 115 time = { 100 116 shred = 2.5; 101 117 }; ................................................................................ 156 172 tiles = m.tiles or 157 173 (m.tone and { 158 174 string.format('default_stone.png^[colorizehsl:%s:%s:%s', 159 175 m.tone.hue, m.tone.sat, m.tone.lum) 160 176 }) or {'default_stone.png'}; 161 177 groups = grp; 162 178 drop = m.rocks or ''; 179 + sounds = hardSounds; 163 180 _starlit = { 164 181 kind = 'block'; 165 182 elements = m.elements; 166 183 fab = m.fab; 167 184 recover = m.recover; 168 185 recover_vary = m.recover_vary; 169 186 };
Modified mods/starlit/user.lua from [fe75c1df99] to [910641ec39].
55 55 weapon = {primary = nil, secondary = nil}; 56 56 psi = {primary = nil, secondary = nil}; 57 57 maneuver = nil; 58 58 }; 59 59 pref = { 60 60 calendar = 'commune'; 61 61 }; 62 + overlays = {}; 62 63 } 63 64 end; 64 65 __index = { 66 + -------------- 67 + -- overlays -- 68 + -------------- 69 + updateOverlays = function(self) 70 + local phys = { 71 + speed = self.pheno:trait('speed',1); 72 + jump = self.pheno:trait('jump',1); 73 + gravity = 1; 74 + speed_climb = 1; 75 + speed_crouch = 1; 76 + speed_walk = 1; 77 + acceleration_default = 1; 78 + acceleration_air = 1; 79 + } 80 + for i, o in ipairs(self.overlays) do o(phys) end 81 + self.entity:set_physics_override(phys) 82 + end; 83 + overlay = function(self, o) 84 + local id = #self.overlays+1 85 + self.overlays[id] = o 86 + self:updateOverlays() 87 + return id 88 + end; 89 + deleteOverlay = function(self, id) 90 + table.remove(self.overlays, id) 91 + self:updateOverlays() 92 + end; 93 + 94 + -------------- 95 + -- personae -- 96 + -------------- 65 97 pullPersona = function(self) 66 98 -- if later records are added in public updates, extend this function to merge them 67 99 -- into one object 68 100 local s = userStore(self.entity) 69 101 self.persona = s.read 'persona' 70 102 self.pheno = starlit.world.species.pheno(self.persona.species, self.persona.speciesVariant) 71 103 end; 72 104 pushPersona = function(self) 73 105 local s = userStore(self.entity) 74 106 s.write('persona', self.persona) 75 107 end; 108 + 76 109 uiColor = function(self) return lib.color {hue=238,sat=.5,lum=.5} end; 110 + 111 + ----------- 112 + -- stats -- 113 + ----------- 77 114 statDelta = function(self, stat, d, cause, abs) 78 115 local dt = self.persona.statDeltas 79 116 local min, max, base = self:statRange(stat) 80 117 if abs then 81 118 if d == true then d = max 82 119 elseif d == false then d = min end 83 120 end ................................................................................ 97 134 self:pushPersona() 98 135 end 99 136 100 137 101 138 self:updateHUD() 102 139 -- TODO trigger relevant animations? 103 140 end; 104 - lookupSpecies = function(self) 105 - return starlit.world.species.lookup(self.persona.species, self.persona.speciesVariant) 106 - end; 107 - phenoTrait = function(self, trait, dflt) 108 --- local s,v = self:lookupSpecies() 109 --- return v.traits[trait] or s.traits[trait] or 0 110 - return self.pheno:trait(trait, dflt) 111 - end; 112 141 statRange = function(self, stat) --> min, max, base 113 142 return starlit.world.species.statRange( 114 143 self.persona.species, self.persona.speciesVariant, stat) 115 144 end; 116 145 effectiveStat = function(self, stat) 117 146 local val 118 147 local min, max, base = self:statRange(stat) ................................................................................ 124 153 else 125 154 val = base + self.persona.statDeltas[stat] or 0 126 155 end 127 156 128 157 local d = max - min 129 158 return val, (val - min) / d 130 159 end; 160 + 161 + --------------- 162 + -- phenotype -- 163 + --------------- 164 + lookupSpecies = function(self) 165 + return starlit.world.species.lookup(self.persona.species, self.persona.speciesVariant) 166 + end; 167 + phenoTrait = function(self, trait, dflt) 168 +-- local s,v = self:lookupSpecies() 169 +-- return v.traits[trait] or s.traits[trait] or 0 170 + return self.pheno:trait(trait, dflt) 171 + end; 131 172 damageModifier = function(self, kind, amt) 132 173 if kind == 'bluntForceTrauma' then 133 174 local std = self:phenoTrait 'sturdiness' 134 175 if std < 0 then 135 176 amt = amt / 1+std 136 177 else 137 178 amt = amt * 1-std 138 179 end 139 180 end 140 181 return amt 141 182 end; 183 + 184 + --------- 185 + -- HUD -- 186 + --------- 142 187 attachImage = function(self, def) 143 188 local user = self.entity 144 189 local img = {} 145 190 img.id = user:hud_add { 146 191 type = 'image'; 147 192 text = def.tex; 148 193 scale = def.scale; ................................................................................ 380 425 align = {x=0, y=-1}; 381 426 z = -1; 382 427 update = function(user, set) 383 428 set('text', hudAdjustBacklight(hudCenterBG):render()) 384 429 end; 385 430 }; 386 431 end; 387 - -- horrible horrible HACK 388 - setModeHand = function(self) 389 - local inv = self.entity:get_inventory() 390 - local hnd 391 - if self.actMode == 'off' 392 - then hnd = ItemStack('starlit:_hand_dig') 393 - else hnd = ItemStack() 432 + deleteHUD = function(self) 433 + for name, e in pairs(self.hud.elt) do 434 + self:hud_delete(e.id) 394 435 end 395 - inv:set_stack('hand', 1, hnd) 396 436 end; 437 + updateHUD = function(self) 438 + for name, e in pairs(self.hud.elt) do 439 + if e.update then e.update() end 440 + end 441 + end; 442 + 443 + --------------------- 444 + -- actions & modes -- 445 + --------------------- 397 446 onModeChange = function(self, oldMode, silent) 398 447 self.hud.elt.crosshair.update() 399 448 if not silent then 400 449 local sfxt = { 401 450 off = 'starlit-mode-off'; 402 451 nano = 'starlit-mode-nano'; 403 452 psi = 'starlit-mode-psi'; ................................................................................ 413 462 local oldMode = self.actMode 414 463 self.actMode = mode 415 464 self:onModeChange(oldMode, silent) 416 465 if mode ~= oldMode then 417 466 starlit.ui.setupForUser(self) 418 467 end 419 468 end; 420 - deleteHUD = function(self) 421 - for name, e in pairs(self.hud.elt) do 422 - self:hud_delete(e.id) 469 + setModeHand = function(self) -- horrible horrible HACK 470 + local inv = self.entity:get_inventory() 471 + local hnd 472 + if self.actMode == 'off' 473 + then hnd = ItemStack('starlit:_hand_dig') 474 + else hnd = ItemStack() 423 475 end 476 + inv:set_stack('hand', 1, hnd) 424 477 end; 425 - updateHUD = function(self) 426 - for name, e in pairs(self.hud.elt) do 427 - if e.update then e.update() end 428 - end 429 - end; 478 + 479 + --------------------- 480 + -- intel-gathering -- 481 + --------------------- 430 482 clientInfo = function(self) 431 483 return minetest.get_player_information(self.name) 432 484 end; 485 + species = function(self) 486 + return starlit.world.species.index[self.persona.species] 487 + end; 488 + 489 + -------------------- 490 + -- event handlers -- 491 + -------------------- 433 492 onSignup = function(self) 434 493 local meta = self.entity:get_meta() 435 494 local inv = self.entity:get_inventory() 436 495 -- the sizes indicated here are MAXIMA. limitations on e.g. the number of elements that may be carried are defined by your suit and enforced through callbacks and UI generation code, not inventory size 437 496 inv:set_size('main', 6) -- carried items and tools. main hotbar. 438 497 inv:set_size('hand', 1) -- horrible hack to allow both tools and intrinsics 439 498 ................................................................................ 471 530 giveGifts('starlit_suit_canisters', gifts.suitCans) 472 531 473 532 giveGifts('main', gifts.carry) 474 533 475 534 self:reconfigureSuit() 476 535 477 536 -- i feel like there has to be a better way 478 - local cx = math.random(-500,500) 537 + local posrng = starlit.world.seedbank[0x13f19] -- TODO player-specific seed 538 + local cx = posrng:int(-500,500) --math.random(-500,500) 479 539 local iter, startPoint = 1 480 540 repeat local temp = -100 481 - local cz = math.random(-500,500) 541 + local cz = posrng:int(-500,500) 482 542 local cy = minetest.get_spawn_level(cx, cz) 483 543 if cy then 484 544 startPoint = vector.new(cx,cy,cz) 485 545 temp = starlit.world.climate.eval(startPoint,.5,.5).surfaceTemp 486 546 end 487 547 iter = iter + 1 488 548 if iter > 100 then break end -- avoid infiniloop in pathological conditions ................................................................................ 597 657 } 598 658 me:set_eye_offset(nil, vector.new(3,-.2,10)) 599 659 -- TODO set_clouds speed in accordance with wind 600 660 starlit.world.species.setupEntity(me, self.persona) 601 661 starlit.ui.setupForUser(self) 602 662 self:createHUD() 603 663 self:updateSuit() 664 + self:updateOverlays() 604 665 end; 666 + onPart = function(self) 667 + starlit.liveUI [self.name] = nil 668 + starlit.activeUI [self.name] = nil 669 + starlit.activeUsers[self.name] = nil 670 + end; 671 + 672 + ----------------------------- 673 + -- environment suit & body -- 674 + ----------------------------- 605 675 suitStack = function(self) 606 676 return self.entity:get_inventory():get_stack('starlit_suit', 1) 607 677 end; 608 678 suitSound = function(self, sfx) 609 679 -- trigger a sound effect from the player's suit computer 610 680 minetest.sound_play(sfx, {object=self.entity, max_hear_distance=4}, true) 611 681 end; ................................................................................ 630 700 sfx = 'starlit-power-up' 631 701 elseif state == 'powerSave' or os == 'powerSave' then 632 702 sfx = 'starlit-configure' 633 703 end 634 704 if sfx then self:suitSound(sfx) end 635 705 end 636 706 end; 637 - species = function(self) 638 - return starlit.world.species.index[self.persona.species] 639 - end; 640 707 updateBody = function(self) 641 708 local adornment = {} 642 709 local suitStack = self:suitStack() 643 710 if suitStack and not suitStack:is_empty() then 644 711 local suit = suitStack:get_definition()._starlit.suit 645 712 suit.adorn(adornment, suitStack, self.persona) 646 713 end ................................................................................ 726 793 -- TODO display power use icon 727 794 end 728 795 return supply, wasteHeat 729 796 end; 730 797 naked = function(self) 731 798 return self:suitStack():is_empty() 732 799 end; 733 - onPart = function(self) 734 - starlit.liveUI [self.name] = nil 735 - starlit.activeUI [self.name] = nil 736 - starlit.activeUsers[self.name] = nil 737 - end; 800 + 801 + -------- 802 + -- ui -- 803 + -------- 738 804 openUI = function(self, id, page, ...) 739 805 local ui = assert(starlit.interface.db[id]) 740 806 ui:open(self, page, ...) 741 807 end; 742 808 onRespond = function(self, ui, state, resp) 743 809 ui:action(self, state, resp) 744 810 end; 745 - 746 - updateWeather = function(self) 747 - end; 748 - 749 - canInteract = function(self, with) 750 - return true; -- TODO 751 - end; 752 - 753 811 trigger = function(self, which, how) 754 812 local p 755 813 local wld = self.entity:get_wielded_item() 756 814 if which == 'maneuver' then 757 815 p = self.power.maneuver 758 816 elseif which == 'retarget' then 759 817 self.action.prog = {} ................................................................................ 783 841 end 784 842 local sw = starlit.item.sw.db[pgm.body.pgmId] 785 843 run = assert(sw.run, 'missing run() for active software ability ' .. pgm.body.pgmId) 786 844 break 787 845 end 788 846 end 789 847 end 848 + elseif p.ref then 849 + run = p.ref.run 790 850 else 791 851 error('bad ability pointer ' .. dump(p)) 792 852 end 793 853 if run then 794 854 run(self, ctx) 795 855 return true 796 856 end 797 857 return false 798 858 end; 859 + 860 + ------------- 861 + -- weather -- 862 + ------------- 863 + updateWeather = function(self) 864 + end; 865 + 866 + canInteract = function(self, with) 867 + return true; -- TODO 868 + end; 869 + 870 + --------------- 871 + -- inventory -- 872 + --------------- 799 873 give = function(self, item) 800 874 local inv = self.entity:get_inventory() 801 875 local function is(grp) 802 876 return minetest.get_item_group(item:get_name(), grp) ~= 0 803 877 end 804 878 -- TODO notif popups 805 879 if is 'specialInventory' then ................................................................................ 847 921 local dehydration = p:trait 'dehydration' * biointerval 848 922 -- you dehydrate faster in higher temp 849 923 dehydration = dehydration * math.max(1, starlit.world.climate.temp(u.entity:get_pos()) / 10) 850 924 851 925 u:statDelta('nutrition', -bmr) 852 926 u:statDelta('hydration', -dehydration) 853 927 854 - if u:effectiveStat 'nutrition' == 0 then 855 - -- starvation 856 - end 928 + local moralePenalty = -1 -- 1min/min 929 + local fatiguePenalty = 1 -- 1min/min 930 + local heatPenalty = 1 -- stamina regen is divided by this 857 931 858 - if u:effectiveStat 'hydration' == 0 then 859 - -- dying of thirst 932 + do local warmth = u:effectiveStat 'warmth' 933 + local tempRange = u:species().tempRange 934 + local tComfMin, tComfMax = tempRange.comfort[1], tempRange.comfort[2] 935 + local tempDiff = 0 936 + if warmth < tComfMin then 937 + tempDiff = math.abs(warmth-tComfMin) 938 + elseif warmth > tComfMax then 939 + tempDiff = math.abs(warmth-tComfMax) 940 + end 941 + moralePenalty = moralePenalty + tempDiff 942 + heatPenalty = heatPenalty + tempDiff 860 943 end 861 944 945 + -- penalize heavy phys. activity 946 + local stamina, sp = u:effectiveStat 'stamina' 947 + fatiguePenalty = fatiguePenalty * (1 + 9*(1-sp)) 948 + 949 + local food = u:effectiveStat 'nutrition' 950 + local water = u:effectiveStat 'hydration' 862 951 local rads = u:effectiveStat 'irradiation' 952 + if food < 1000 then moralePenalty = moralePenalty + (1 - (food/1000)) * 5 end 953 + if water < 1 then moralePenalty = moralePenalty + (1 - (water/1)) * 10 end 954 + 863 955 if rads > 0 then 864 956 u:statDelta('irradiation', -0.0001 * biointerval) 957 + local moraleDrainFac = 2^(rads / 2) 958 + moralePenalty = moralePenalty * moraleDrainFac 959 + end 960 + 961 + u:statDelta('morale', moralePenalty * biointerval) 962 + u:statDelta('fatigue', fatiguePenalty * biointerval) 963 + 964 + if food == 0 then -- starvation 965 + u:statDelta('health', -5*biointerval) 966 + end 967 + 968 + if water == 0 then -- dying of thirst 969 + u:statDelta('health', -20*biointerval) 865 970 end 866 971 972 + if sp < 1.0 then 973 + u:statDelta('stamina', u:effectiveStat 'staminaRegen' / heatPenalty) 974 + end 867 975 end 868 976 end) 869 977 870 978 local cbit = { 871 979 up = 0x001; 872 980 down = 0x002; 873 981 left = 0x004; ................................................................................ 893 1001 return mustHalt 894 1002 else return doNothing end 895 1003 end 896 1004 local skipBits = 0 897 1005 if user.action.bits ~= bits then 898 1006 local mPrimary = what(cbit.dig) 899 1007 local mSecondary = what(cbit.put) 1008 + local mManeuver = what(cbit.manv) 900 1009 if mPrimary == mustInit then -- ENGINE-BUG 901 1010 user.action.tgt = {type='nothing'} 902 1011 user.action.prog = {} 903 1012 elseif mPrimary == mustHalt then 904 1013 user:trigger('primary', {state='halt'}) 905 1014 end 906 1015 if mSecondary == mustHalt then 907 1016 user:trigger('secondary', {state='halt'}) 908 1017 end 1018 + if mManeuver == mustInit then 1019 + user:trigger('maneuver', {state='init'}) 1020 + elseif mManeuver == mustHalt then 1021 + user:trigger('maneuver', {state='halt'}) 1022 + end 909 1023 end 910 1024 --bits = bit.band(bits, bit.bnot(skipBits)) 911 - if bit.band(bits, cbit.dig)~=0 then 912 - user:trigger('primary', {state='prog', delta=delta}) 1025 + local function prog(what) 1026 + user:trigger(what, {state='prog', delta=delta}) 913 1027 end 914 - if bit.band(bits, cbit.put)~=0 then 915 - user:trigger('secondary', {state='prog', delta=delta}) 916 - end 1028 + if bit.band(bits, cbit.dig)~=0 then prog 'primary' end 1029 + if bit.band(bits, cbit.put)~=0 then prog 'secondary' end 1030 + if bit.band(bits, cbit.manv)~=0 then prog 'maneuver' end 917 1031 user.action.bits = bits 918 1032 -- ENGINE-BUG: dig and put are not handled equally in the 919 1033 -- engine. it is possible for the put bit to get stuck on 920 1034 -- if the key is hammered while the player is not moving. 921 1035 -- the bit will release as soon as the player looks or turns 922 1036 -- nonetheless this is obnoxious 923 1037 end 924 1038 end)
Modified mods/starlit/world.lua from [4823845880] to [cdaabd4e00].
96 96 world.ecology.plants.foreach('starlit:plant-gen', {}, function(id, b) 97 97 local stageCt = #b.stages 98 98 local function stageID(n) 99 99 if n == stageCt then return id end 100 100 return id .. string.format('_stage_%s', n) 101 101 end 102 102 b.stageNodes = {} 103 + b.req = b.req or {} 103 104 local function regStage(n, st) 104 105 local base = { 105 106 description = b.name; 106 107 drawtype = "plantlike"; 107 108 tiles = { tostring(st.tex) }; 108 109 paramtype = "light"; 109 110 paramtype2 = "meshoptions"; 110 111 place_param2 = b.meshOpt; 111 112 walkable = false; 112 113 buildable_to = true; 113 114 groups = { 114 115 plant = 1; 115 116 plant_grow = stageCt ~= n and 1 or 0; 117 + attached_node = 3; 116 118 }; 117 119 drop = st.drop; 118 120 _starlit = { 119 121 plant = { 120 122 id = id, stage = n; 121 123 }; 122 124 recover = starlit.type.fab { ................................................................................ 130 132 potassium = rng:int(0,1); 131 133 } 132 134 }; 133 135 end; 134 136 }; 135 137 } 136 138 if st.swap then 137 - base.node_dig_prediction = stageID(st.swap) 139 + base.node_dig_prediction = "" 138 140 function base.after_dig_node(pos, node, digger) 139 141 node.name = stageID(st.swap) 140 142 minetest.swap_node(pos, node) 141 143 return true 142 144 end 143 145 end 144 146 if st.biolum then base.light_source = st.biolum; end ................................................................................ 232 234 user:statDelta('health', -dmg) 233 235 end 234 236 end 235 237 end) 236 238 237 239 238 240 world.ecology.trees.foreach('starlit:tree-gen', {}, function(id, t) 239 - local dec = { 240 - deco_type = 'lsystem'; 241 - treedef = t.def; 242 - } 243 - for k,v in pairs(t.decorate) do dec[k]=v end 244 - minetest.register_decoration(dec) 241 + for i,td in ipairs(t.decorate) do 242 + local dec = { 243 + deco_type = 'lsystem'; 244 + treedef = t.def; 245 + } 246 + for k,v in pairs(td) do dec[k]=v end 247 + minetest.register_decoration(dec) 248 + end 245 249 end) 246 250 247 251 minetest.register_abm { 248 252 label = "plant growth"; 249 253 nodenames = {'group:plant_grow'}; 250 254 chance = 15; 251 255 interval = 20; 252 256 catch_up = true; 253 257 action = function(pos, node) 254 258 local def = minetest.registered_nodes[node.name]._starlit.plant 255 - local plant = starlit.world.ecology.plants.db[def.id] 256 - local nextStage = plant.stageNodes[def.stage + 1] 257 - minetest.swap_node(pos, {name=nextStage}) 259 + -- 5 W: maximum power for UV lamps 260 + -- 7 W: maximum solar power 261 + local uv = (minetest.get_natural_light(pos) / 15) * 7 262 + -- TODO compute artificial contribution 263 + local req = lib.tbl.defaults({ 264 + uv = 3; 265 + soil = 'soil'; 266 + temp = -10; 267 + humid = nil; 268 + }, def.growReq); 269 + 270 + -- TODO check other reqs 271 + 272 + if uv > req.uv then 273 + local plant = starlit.world.ecology.plants.db[def.id] 274 + local nextStage = plant.stageNodes[def.stage + 1] 275 + minetest.swap_node(pos, {name=nextStage}) 276 + end 258 277 end; 259 278 }
Modified mods/vtlib/math.lua from [9f5dd95326] to [6a568676fe].
129 129 return fn.rng(PcgRandom(self.seed+n):next()) 130 130 end; 131 131 __add = function(self, n) 132 132 return fn.seedbank(self.seed + n) 133 133 end; 134 134 } 135 135 -- function fn.vlerp 136 + 137 +function fn.timespec(n) 138 + if n == 0 then return '0s' end 139 + if n < 0 then return '-' .. fn.timespec(n*-1) end 140 + 141 + local sec = n % 60 142 + local hr = math.floor(n / 60) 143 + local spec = {} 144 + 145 + if sec ~= 0 then table.insert(spec, string.format("%ss", sec)) end 146 + if hr ~= 0 then table.insert(spec, string.format("%shr", hr)) end 147 + return table.concat(spec, ' ') 148 +end 136 149 return fn
Modified starlit.ct from [3827ce4fcb] to [990b095f3f].
38 38 39 39 p11143: https://github.com/minetest/minetest/pull/11143.diff 40 40 41 41 ### shadows 42 42 i was delighted to see dynamic shadows land in minetest, and i hope the implementation will eventually mature. however, as it stands, there are severe issues with shadows that make them essentially incompatible with complex meshes like the Starlit player character meshes. for the sake of those who don't mind these glitches, Starlit does enable shadows, but i unfortunately have to recommend that you disable them until the minetest devs get their act together on this feature. 43 43 44 44 ## gameplay 45 +the most important thing to understand about starlit is that is is [*mean], by design. 46 + 47 +* chance plays an important role. your escape pod might land in the midst of a lush, temperate forest with plenty of nearby shipwrecks to scavenge. or it might land in the exact geographic center of a vast, harsh desert that your suit's cooling systems can't protect you from, ten klicks from anything of value. "unfair", you say? tough. Thousand Petal doesn't care about your feelings. 48 +* death is much worse than a slap on the wrist. when you die, you drop your possessions and your suit, and respawn naked at your spawn point. this is a serious danger, as you might be kilometers away from your spawn point -- and there's no guarantee someone else won't take your suit before you can find your way back to it. good luck crossing long distances without climate control! if you haven't carefully prepared for this eventuality by keeping a spare suit by your spawn point, death can be devastating, to the point of making the game unsurvivable without another player's help. 49 + 45 50 starlit is somewhat unusual in how it uses the minetest engine. it's a voxel game but not of the minecraft variety. 46 51 47 52 ### controls 48 53 summon your Suit Interface by pressing the [*E] / [*Inventory] key. this will allow you to move items around in your inventory, but more importantly, it also allows you select or configure your Interaction Mode. 49 54 50 55 the top three buttons can be used to select (or deactivate) an Interaction Mode. an Interaction Mode can be configured by pressing the button immediately below. the active Interaction Mode controls the behavior of the mouse buttons when no item is selected in the hotbar. 51 56