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