Comment: | better alarm LEDs, continue work on matter compiler UI, hack around gravitational horrorscape (i.e. stop shitting all over the server's `minetest.conf`), better stat interface, tweak some compute stats, be more generous with starting battery loadout, mercilessly squash numberless bugs beneath my jackbooted heel |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
953151446f688fc9771fdc5fe3b2278a |
User & Date: | lexi on 2024-05-05 19:31:39 |
Other Links: | manifest | tags |
2024-05-06
| ||
16:20 | complete (-ish) matter compiler UI (power drain still missing), add printable chemical light check-in: 3df08bd5ac user: lexi tags: trunk | |
2024-05-05
| ||
19:31 | better alarm LEDs, continue work on matter compiler UI, hack around gravitational horrorscape (i.e. stop shitting all over the server's `minetest.conf`), better stat interface, tweak some compute stats, be more generous with starting battery loadout, mercilessly squash numberless bugs beneath my jackbooted heel check-in: 953151446f user: lexi tags: trunk | |
2024-05-04
| ||
22:41 | add beginnings of matter compiler UI, check in missing files check-in: 0e7832a24c user: lexi tags: trunk | |
Modified mods/starlit-electronics/init.lua from [fff344db38] to [d82ba893dd].
275 275 -- firstborn ("god-tier"): exceptional 276 276 277 277 local batteryTiers = { 278 278 makeshift = { 279 279 name = 'Makeshift'; capacity = .5, decay = 3, leak = 2, dischargeRate = 1, 280 280 fab = starlit.type.fab { 281 281 element = {copper=10}; 282 + cost = {power = 0.3}; 283 + time = {print = .25}; 282 284 }; 283 285 desc = "Every attosecond this electrical abomination doesn't explode in your face is but the unearned grace of the Wild Gods."; 284 286 complexity = 1; 285 287 sw = {rarity = 1}; 286 288 }; 287 289 imperial = { 288 290 name = 'Imperial'; capacity = 2, decay = 2, leak = 2, dischargeRate = 2; 289 291 fab = starlit.type.fab { 290 292 element = {copper=15, iron = 20}; 291 293 size = { print = 0.1 }; 294 + cost = {power = 2}; 295 + time = {print = .5}; 292 296 }; 293 297 desc = "The Empire's native technology is a lumbering titan: bulky, inefficient, unreliable, ugly, and awesomely powerful. Their batteries are no exception, with raw capacity and throughput that exceed even Usukinwya designs."; 294 298 drm = 1; 295 299 complexity = 2; 296 300 sw = {rarity = 2}; 297 301 }; 298 302 commune = { 299 303 name = 'Commune'; capacity = 1, decay = .5, leak = .2, dischargeRate = 1; 300 304 fab = starlit.type.fab { 301 305 element = {vanadium = 50}; 302 306 metal = {steel=10}; 303 307 size = { print = 0.05 }; 308 + cost = {power = 1}; 304 309 }; 305 310 desc = "The Commune's proprietary battery designs prioritize reliability, compactness, and maintenance concerns above raw throughput, with an elegance of engineering and design that would make a Su'ikuri cry."; 306 311 complexity = 5; 307 312 sw = {rarity = 3}; 308 313 }; 309 314 usukwinya = { 310 315 name = 'Usukwinya'; capacity = 2, decay = 1, leak = 1, dischargeRate = 1.5, 311 316 fab = starlit.type.fab { 312 317 element = {argon=10}; 313 318 metal = {vanadium=30}; 314 319 size = { print = 0.07 }; 320 + cost = {power = .8}; 315 321 }; 316 322 desc = "A race of consummate value engineers, the Usukwinya have spent thousands of years refining their tech to be as cheap to build as possible, without compromising much on quality. The Tradebirds drive an infamously hard bargain, but their batteries are more than worth their meagre cost."; 317 323 drm = 2; 318 324 sw = {rarity = 10}; 319 325 complexity = 15; 320 326 }; 321 327 eluthrai = { 322 328 name = 'Eluthrai'; capacity = 3, decay = .4, leak = .1, dischargeRate = 1.5, 323 329 fab = starlit.type.fab { 324 330 element = {beryllium=20, platinum=20, technetium = 1}; 325 331 metal = {cinderstone = 10}; 326 332 size = { print = 0.03 }; 333 + cost = {power = 10}; 334 + time = {print = 2}; 327 335 }; 328 336 desc = "The uncompromising Eluthrai are never satisfied until every quantifiable characteristic of their tech is maximally optimised down to the picoscale. Their batteries are some of the best in the Reach, and unquestionably the most expensive -- especially for those lesser races trying to copy the designs without the benefit of the sublime autofabricator ecosystem of the Eluthrai themselves."; 329 337 complexity = 200; 330 338 sw = {rarity = 0}; -- you think you're gonna buy eluthran schematics on SuperDiscountNanoWare.space?? 331 339 }; 332 340 firstborn = { 333 341 name = 'Firstborn'; capacity = 5, decay = 0.1, leak = 0, dischargeRate = 3; 334 342 fab = starlit.type.fab { 335 343 element = {neodymium=20, xenon=150, technetium=5}; 336 344 metal = {sunsteel = 10}; 337 345 crystal = {astrite = 1}; 338 346 size = { print = 0.05 }; 347 + cost = {power = 50}; 348 + time = {print = 4}; 339 349 }; 340 350 desc = "Firstborn engineering seamlessly merges psionic effects with a mastery of the physical universe unattained by even the greatest of the living Starsouls. Their batteries reach levels of performance that strongly imply Quantum Gravity Theory -- and several major holy books -- need to be rewritten. From the ground up."; 341 351 complexity = 1000; 342 352 sw = {rarity = 0}; -- lol no 343 353 }; 344 354 } 345 355 346 356 local batterySizes = { 347 - small = {name = 'Small', capacity = .5, dischargeRate = .5, complexity = 1, matMult = .5, fab = starlit.type.fab {size={print=0.1}}}; 348 - mid = { capacity = 1, dischargeRate = 1, complexity = 1, matMult = 1, fab = starlit.type.fab {size={print=0.3}}}; 349 - large = {name = 'Large', capacity = 2, dischargeRate = 1.5, complexity = 1, matMult = 1.5, fab = starlit.type.fab {size={print=0.5}}}; 350 - huge = {name = 'Huge', capacity = 3, dischargeRate = 2, complexity = 1, matMult = 2, fab = starlit.type.fab {size={print=0.8}}}; 357 + small = {name = 'Small', capacity = .5, dischargeRate = .5, complexity = 1, matMult = .5, 358 + fab = starlit.type.fab {size={print=0.1},cost={power=.5},time={print=25}}}; 359 + mid = { capacity = 1, dischargeRate = 1, complexity = 1, matMult = 1, 360 + fab = starlit.type.fab {size={print=0.3},cost={power=1},time={print=40}}}; 361 + large = {name = 'Large', capacity = 2, dischargeRate = 1.5, complexity = 1, matMult = 1.5, 362 + fab = starlit.type.fab {size={print=0.5},cost={power=2},time={print=60}}}; 363 + huge = {name = 'Huge', capacity = 3, dischargeRate = 2, complexity = 1, matMult = 2, 364 + fab = starlit.type.fab {size={print=0.8},cost={power=8},time={print=120}}}; 351 365 } 352 366 353 367 local batteryTypes = { 354 368 supercapacitor = { 355 369 name = 'Supercapacitor'; 356 370 desc = 'Room-temperature superconductors make for very reliable, high-dischargeRate, but low-capacity batteries.'; 357 371 fab = starlit.type.fab { 358 372 metal = { enodium = 5 }; 359 373 size = {print=0.8}; 374 + cost = {power = 1e3}; 360 375 }; 361 376 sw = { 362 377 cost = { 363 - cycles = 5e9; -- 5 bil cycles 364 - ram = 10e9; -- 10GB 378 + cycles = 48e9; -- 48 bil cycles 379 + ram = 4e9; -- 10GB 365 380 }; 366 381 pgmSize = 2e9; -- 2GB 367 382 rarity = 5; 368 383 }; 369 384 capacity = 50e3, dischargeRate = 1000; 370 385 leak = 0, decay = 1e-6; 371 386 ................................................................................ 373 388 }; 374 389 chemical = { 375 390 name = 'Chemical'; 376 391 desc = ''; 377 392 fab = starlit.type.fab { 378 393 element = { lithium = 3 }; 379 394 size = {print=1.0}; 395 + cost = {power = .5e3}; 380 396 }; 381 397 sw = { 382 398 cost = { 383 - cycles = 1e9; -- 1 bil cycles 384 - ram = 2e9; -- 2GB 399 + cycles = 16e9; -- 16 bil cycles 400 + ram = 1e9; -- 1GB 385 401 }; 386 402 pgmSize = 512e6; -- 512MB 387 403 rarity = 2; 388 404 }; 389 405 capacity = 200e3, dischargeRate = 200; 390 406 leak = 0.2, decay = 1e-2; 391 407 complexity = 1; ................................................................................ 393 409 carbon = { 394 410 name = 'Carbon'; 395 411 desc = 'Carbon nanotubes form the basis of many important metamaterials, chief among them power-polymer.'; 396 412 capacity = 1; 397 413 fab = starlit.type.fab { 398 414 element = { carbon = 40 }; 399 415 size = {print=0.5}; 416 + cost = {power = 2.5e3}; 400 417 }; 401 418 sw = { 402 419 cost = { 403 - cycles = 50e9; -- 50 bil cycles 404 - ram = 64e9; -- 64GB 420 + cycles = 256e9; -- 256 bil cycles 421 + ram = 16e9; -- 64GB 405 422 }; 406 - pgmSize = 1e9; -- 1GB 423 + pgmSize = 4e9; -- 4GB 407 424 rarity = 10; 408 425 }; 409 426 capacity = 100e3, dischargeRate = 500; 410 427 leak = 0.1, decay = 1e-3; 411 428 complexity = 10; 412 429 }; 413 430 hybrid = { ................................................................................ 416 433 capacity = 1; 417 434 fab = starlit.type.fab { 418 435 element = { 419 436 lithium = 10; 420 437 carbon = 20; 421 438 }; 422 439 size = {print=1.5}; 440 + cost = {power = 10e3}; 423 441 }; 424 442 sw = { 425 443 cost = { 426 - cycles = 65e9; -- 65 bil cycles 427 - ram = 96e9; -- 96GB 444 + cycles = 512e9; -- 512 bil cycles 445 + ram = 24e9; -- 96GB 428 446 }; 429 - pgmSize = 5e9; -- 5GB 447 + pgmSize = 7e9; -- 7GB 430 448 rarity = 15; 431 449 }; 432 450 capacity = 300e3, dischargeRate = 350; 433 451 leak = 0.3, decay = 1e-5; 434 452 complexity = 30; 435 453 }; 436 454 } 437 455 456 +--[[ 438 457 local function elemath(dest, src, mult) 439 458 dest = dest or {} 440 459 for k,v in pairs(src) do 441 460 if not dest[k] then dest[k] = 0 end 442 461 dest[k] = dest[k] + v*mult 443 462 end 444 463 return dest 445 -end 464 +end]] 446 465 447 466 for bTypeName, bType in pairs(batteryTypes) do 448 467 for bTierName, bTier in pairs(batteryTiers) do 449 468 for bSizeName, bSize in pairs(batterySizes) do 450 469 -- elemath(elementCost, bType.fab.element or {}, bSize.matMult) 451 470 -- elemath(elementCost, bTier.fab.element or {}, bSize.matMult) 452 471 -- elemath(metalCost, bType.fab.metal or {}, bSize.matMult) ................................................................................ 764 783 }) 765 784 end) 766 785 767 786 -- in case other mods want to define their own tiers 768 787 E.chip.tiers = lib.registry.mk 'starlit_electronics:chipTiers' 769 788 E.chip.tiers.meld { 770 789 -- GP chips 771 - tiny = {name = 'Tiny Chip', clockRate = 512e3, flash = 4096, ram = 1024, powerEfficiency = 1e9, size = 1}; 772 - small = {name = 'Small Chip', clockRate = 128e6, flash = 512e6, ram = 512e6, powerEfficiency = 1e8, size = 3}; 773 - med = {name = 'Chip', clockRate = 1e9, flash = 4e9, ram = 4e9, powerEfficiency = 1e7, size = 6}; 774 - large = {name = 'Large Chip', clockRate = 2e9, flash = 8e9, ram = 8e9, powerEfficiency = 1e6, size = 8}; 790 + tiny = {name = 'Tiny Chip', clockRate = 512e3, flash = 4096, ram = 1024, powerEfficiency = 1e10, size = 1}; 791 + small = {name = 'Small Chip', clockRate = 128e6, flash = 512e6, ram = 512e6, powerEfficiency = 1e9, size = 3}; 792 + med = {name = 'Chip', clockRate = 1e9, flash = 4e9, ram = 4e9, powerEfficiency = 1e8, size = 6}; 793 + large = {name = 'Large Chip', clockRate = 2e9, flash = 8e9, ram = 8e9, powerEfficiency = 1e7, size = 8}; 775 794 -- specialized chips 776 - compute = {name = 'Compute Chip', clockRate = 4e9, flash = 24e6, ram = 64e9, powerEfficiency = 1e8, size = 4}; 777 - data = {name = 'Data Chip', clockRate = 128e3, flash = 2e12, ram = 32e3, powerEfficiency = 1e5, size = 4}; 778 - lp = {name = 'Low-Power Chip', clockRate = 128e6, flash = 64e6, ram = 1e9, powerEfficiency = 1e10, size = 4}; 779 - carbon = {name = 'Carbon Chip', clockRate = 64e6, flash = 32e6, ram = 2e6, powerEfficiency = 2e9, size = 2, circ='carbon'}; 795 + compute = {name = 'Compute Chip', clockRate = 4e9, flash = 24e6, ram = 64e9, powerEfficiency = 1e9, size = 4}; 796 + data = {name = 'Data Chip', clockRate = 128e3, flash = 2e12, ram = 32e3, powerEfficiency = 1e6, size = 4}; 797 + lp = {name = 'Low-Power Chip', clockRate = 128e6, flash = 64e6, ram = 1e9, powerEfficiency = 1e11, size = 4}; 798 + carbon = {name = 'Carbon Chip', clockRate = 64e6, flash = 32e6, ram = 2e6, powerEfficiency = 2e10, size = 2, circ='carbon'}; 780 799 } 781 800 782 801 E.chip.tiers.foreach('starlit_electronics:genChips', {}, function(id, t) 783 802 id = t.id or string.format('%s:chip_%s', minetest.get_current_modname(), id) 784 803 local circMat = t.circ or 'silicon'; 785 804 starlit.item.chip.link(id, { 786 805 name = t.name; ................................................................................ 792 811 flag = { 793 812 silicompile = true; 794 813 }; 795 814 time = { 796 815 silicompile = t.size * 24*60; 797 816 }; 798 817 cost = { 799 - energy = 50e3 + t.size * 15e2; 818 + power = 50e3 + t.size * 15e2; 800 819 }; 801 820 element = { 802 821 [circMat] = 50 * t.size; 803 822 copper = 30; 804 823 gold = 15; 805 824 }; 806 825 };
Modified mods/starlit-electronics/sw.lua from [430c447d0b] to [da2672ba3c].
136 136 }; 137 137 run = shredder{range=3, powerDraw=200}; 138 138 }) 139 139 140 140 starlit.item.sw.link('starlit_electronics:compile_commune', { 141 141 name = 'Compile Matter'; 142 142 kind = 'suitPower', powerKind = 'direct'; 143 - desc = "A basic suit matter compiler program, rather slow but ruthlessly optimized for power- and memory-efficiency by some of the Commune's most fanatic coders."; 143 + desc = "A basic suit matter compiler program. It's rather slow, but it's been ruthlessly optimized for size- and memory-efficiency by some of the Commune's most fanatic coders, to the point where every Commune nanosuit can come with the program preinstalled."; 144 144 size = 700e3; 145 145 cost = { 146 - cycles = 300e6; 147 - ram = 2e9; 146 + cycles = 4e9; 147 + ram = .3e9; 148 148 }; 149 149 ui = 'starlit:compile-matter-component'; 150 150 run = function(user, ctx) 151 151 end; 152 152 }) 153 153 154 154 starlit.item.sw.link('starlit_electronics:compile_block_commune', { 155 155 name = 'Compile Block'; 156 156 kind = 'suitPower', powerKind = 'active'; 157 157 desc = "An advanced suit matter compiler program, capable of printing complete devices and structure parts directly into the world."; 158 158 size = 5e6; 159 159 cost = { 160 - cycles = 700e6; 161 - ram = 4e9; 160 + cycles = 8e9; 161 + ram = 1e9; 162 162 }; 163 163 ui = 'starlit:compile-matter-block'; 164 164 run = function(user, ctx) 165 165 end; 166 166 }) 167 + 168 +starlit.item.sw.link('starlit_electronics:compile_imperial', { 169 + name = 'Genesis Deluxe'; 170 + kind = 'suitPower', powerKind = 'direct'; 171 + desc = "House Bascundir has long dominated the matter compiler market in the Crystal Sea. Their firmware is excessively complex due to mountains of specialized edge-case handling, but the end result is certainly speedier than the competitors'."; 172 + size = 2e4; 173 + cost = { 174 + cycles = 100e6; 175 + ram = 1.5e9; 176 + }; 177 + ui = 'starlit:compile-matter-component'; 178 + run = function(user, ctx) 179 + end; 180 +}) 167 181 168 182 do local J = starlit.store.compilerJob 169 183 starlit.item.sw.link('starlit_electronics:driver_compiler_commune', { 170 184 name = 'Matter Compiler'; 171 185 kind = 'driver'; 172 186 desc = "A driver for a standalone matter compiler, suitable for building larger components than your suit alone can handle."; 173 187 size = 850e3; 174 188 cost = { 175 189 cycles = 400e6; 176 - ram = 2e9; 190 + ram = .2e9; 177 191 }; 178 192 ui = 'starlit:device-compile-matter-component'; 179 193 run = function(user, ctx) 180 194 end; 181 195 bgProc = function(user, ctx, interval, runState) 182 196 if runState.flags.compiled == true then return false end 183 197 -- only so many nanides to go around
Modified mods/starlit-scenario/init.lua from [a141e7b70f] to [a805932fc9].
106 106 social = { 107 107 empire = 'workingClass'; 108 108 commune = 'metic'; 109 109 }; 110 110 111 111 startingItems = { 112 112 suit = ItemStack('starlit_suit:suit_survival_commune'); 113 - suitBatteries = {battery 'starlit_electronics:battery_carbon_commune_small'}; 113 + suitBatteries = {battery 'starlit_electronics:battery_carbon_commune_mid'}; 114 114 suitChips = { 115 115 chipLibrary.survivalware; 116 116 -- you didn't notice it earlier, but your Commune environment suit 117 117 -- came with this chip already plugged in. it's apparently true 118 118 -- what they say: the Commune is always prepared for everything. 119 119 -- E V E R Y T H I N G. 120 120 }; ................................................................................ 121 121 suitGuns = {}; 122 122 suitAmmo = {}; 123 123 suitCans = { 124 124 -- ItemStack('starlit_material:canister_small'); 125 125 volume('liquid', 'water', 5); 126 126 }; 127 127 carry = { 128 + battery 'starlit_electronics:battery_carbon_commune_small'; 128 129 chipLibrary.compendium; 129 130 -- you bought this on a whim before you left the Empire, and 130 131 -- just happened to still have it on your person when everything 131 132 -- went straight to the Wild Gods' privy 132 133 }; 133 134 }; 134 135 })
Modified mods/starlit/element.lua from [25b10aa9d6] to [f0333e36f4].
3 3 local M = W.material 4 4 5 5 M.element.foreach('starlit:sort', {}, function(id, m) 6 6 if m.metal then 7 7 M.metal.link(id, { 8 8 name = m.name; 9 9 composition = starlit.type.fab{element = {[id] = 1}}; 10 - color = m.color; 11 10 -- n.b. this is a RATIO: it will be appropriately multiplied 12 - -- for the object in question; e.g a normal chunk will be 13 - -- 100 $element, an ingot will be 1000 $element 11 + -- for the object in question 12 + color = m.color; 13 + elemental = m.name; 14 14 }) 15 15 elseif m.gas then 16 16 M.gas.link(id, { 17 17 name = m.name; 18 18 composition = starlit.type.fab{element = {[id] = 1}}; 19 19 density = m.density; 20 + elemental = m.name; 20 21 }) 21 22 elseif m.liquid then 22 23 M.liquid.link(id, { 23 24 name = m.name; 24 25 composition = starlit.type.fab{element = {[id] = 1}}; 25 26 density = m.density; 27 + elemental = m.name; 26 28 }) 27 29 end 28 30 end) 29 31 30 32 local F = string.format 31 33 32 34 local function mkEltIndicator(composition) ................................................................................ 53 55 indsz, indsz, 54 56 indicator); 55 57 end 56 58 end 57 59 58 60 M.element.foreach('starlit:gen-forms', {}, function(id, m) 59 61 local eltID = F('%s:element_%s', minetest.get_current_modname(), id) 60 - local eltName = F('Elemental %s', lib.str.capitalize(m.name)) 62 +-- local eltName = F('Elemental %s', lib.str.capitalize(m.name)) 61 63 local tt = function(t, d, g) 62 64 return starlit.ui.tooltip { 63 65 title = t, desc = d; 64 66 color = lib.color(0.1,0.2,0.1); 65 67 props = { 66 68 {title = 'Mass', desc = lib.math.si('g', g), affinity='info'} 67 69 } ................................................................................ 90 92 _starlit = { 91 93 mass = 1; 92 94 material = { 93 95 kind = 'element'; 94 96 element = id; 95 97 }; 96 98 fab = starlit.type.fab { 99 + flag = {smelt = m.metal and true or nil}; 97 100 element = comp; 98 101 }; 99 102 }; 100 103 }); 101 104 end 102 105 103 106 --[[ ................................................................................ 121 124 }; 122 125 }); 123 126 ]] 124 127 end) 125 128 126 129 127 130 M.metal.foreach('starlit:gen-forms', {}, function(id, m) 128 - local baseID = F('%s:metal_%s_', minetest.get_current_modname(), id) 129 - local ingotID = baseID .. 'ingot' 130 - local ingotName = F('%s Ingot', lib.str.capitalize(m.name)) 131 - m.form = m.form or {} 132 - m.form.ingot = ingotID 133 - local tt = function(t, d, g) 134 - return starlit.ui.tooltip { 135 - title = t, desc = d; 136 - color = lib.color(0.1,0.1,0.1); 137 - props = { 138 - {title = 'Mass', desc = lib.math.si('g', g), affinity='info'} 131 + if m.elemental then -- avoid multiple forms for same material 132 + m.form = M.element.db[m.elemental].form; 133 + else 134 + local baseID = F('%s:metal_%s_', minetest.get_current_modname(), id) 135 + local brickID = baseID .. 'brick' 136 + local brickName = F('%s Brick', lib.str.capitalize(m.name)) 137 + m.form = m.form or {} 138 + m.form.brick = brickID 139 + local tt = function(t, d, g) 140 + return starlit.ui.tooltip { 141 + title = t, desc = d; 142 + color = lib.color(0.1,0.1,0.1); 143 + props = { 144 + {title = 'Mass', desc = lib.math.si('g', g), affinity='info'} 145 + } 139 146 } 140 - } 141 - end 142 - local mcomp = m.composition:elementalize().element 143 - local function comp(n) 144 - local t = {} 145 - for id, amt in pairs(mcomp) do 146 - t[id] = amt * n 147 + end 148 + local mcomp = m.composition:elementalize().element 149 + local function comp(n) 150 + local t = {} 151 + for id, amt in pairs(mcomp) do 152 + t[id] = amt * n 153 + end 154 + return t 147 155 end 148 - return t 149 - end 150 - local iblit = mkEltIndicator(mcomp) 151 - local function img(s) 152 - return iblit(s:colorize(m.color):render()) 153 - end 156 + local iblit = mkEltIndicator(mcomp) 157 + local function img(s) 158 + return iblit(s:colorize(m.color):render()) 159 + end 154 160 155 - minetest.register_craftitem(ingotID, { 156 - short_description = ingotName; 157 - description = tt(ingotName, F('A solid ingot of %s, ready to be worked by a large matter compiler', m.name), 1e3); 158 - inventory_image = img(lib.image('starlit-item-ingot.png')); 159 - wield_image = lib.image 'starlit-item-ingot.png':colorize(m.color):render(); 160 - groups = {metal = 1, ingot = 1}; 161 - stack_max = 5; 162 - _starlit = { 163 - mass = 1e3; 164 - material = { 165 - kind = 'metal'; 166 - metal = id; 161 + local mass = 1 162 + minetest.register_craftitem(brickID, { 163 + short_description = brickName; 164 + description = tt(brickName, F('A small brick of %s, ready to be worked by a matter compiler', m.name), mass); 165 + inventory_image = img(lib.image('starlit-item-brick.png')); 166 + wield_image = lib.image 'starlit-item-brick.png':colorize(m.color):render(); 167 + groups = {metal = 1, brick = 1}; 168 + stack_max = 500; 169 + _starlit = { 170 + mass = mass; 171 + material = { 172 + kind = 'metal'; 173 + metal = id; 174 + }; 175 + fab = starlit.type.fab { 176 + flag = {smelt=true}; 177 + element = comp(1e3); 178 + }; 167 179 }; 168 - fab = starlit.type.fab { 169 - flag = {smelt=true}; 170 - element = comp(1e3); 171 - }; 172 - }; 173 - }); 174 - 180 + }); 181 + end 175 182 176 183 end) 177 184 178 185 local canisterMeta = lib.marshal.metaStore { 179 186 contents = {key = 'starlit:canister_contents', type = starlit.store.volume}; 180 187 } 181 188 ................................................................................ 227 234 short_description = c.name; 228 235 description = canisterDesc(nil, c); 229 236 inventory_image = c.image or 'starlit-item-element-canister.png'; 230 237 groups = {canister = 1}; 231 238 stack_max = 1; 232 239 _starlit = { 233 240 canister = c; 234 - container = { 235 - handle = function(stack, oldstack) 236 - stack:get_meta():set_string('description', canisterDesc(stack)) 237 - return stack 238 - end; 239 - list = { 240 - elem = { 241 - key = 'starlit:canister_elem'; 242 - accept = 'powder'; 243 - sz = c.slots; 244 - }; 245 - }; 246 - }; 247 241 }; 248 242 }) 249 243 end) 250 244 251 245 function starlit.item.canister.contents(st) 252 246 local m = canisterMeta(st) 253 247 return m.read 'contents'
Modified mods/starlit/fab.lua from [bdd1907d1f] to [a2443e45a4].
12 12 -- * used for determining quantities. that is, 13 13 -- f*x = spec to make x instances of f 14 14 -- 15 15 -- new fab fields must be defined in starlit.type.fab.fields. 16 16 -- this maps a name to fn(a,b,n) -> quant, where a is the first 17 17 -- argument, b is a compounding amount, and n is a quantity of 18 18 -- items to produce. fields that are unnamed will be underwritten 19 + 20 +local fab 19 21 20 22 local function fQuant(a,b,n) return ((a or 0)+(b or 0))*n end 21 23 local function fFac (a,b,n) 22 24 if a == nil and b == nil then return nil end 23 25 local f if a == nil or b == nil then 24 26 f = a or b 25 27 else ................................................................................ 29 31 end 30 32 local function fReq (a,b,n) return a or b end 31 33 local function fFlag (a,b,n) return a and b end 32 34 local function fSize (a,b,n) return math.max(a,b) end 33 35 34 36 local F = string.format 35 37 local lib = starlit.mod.lib 38 + 39 +local function fRawMat(class) 40 + return function(x,n,stack) 41 + local def = stack:get_definition()._starlit 42 + if not def.material then return 0 end 43 + local mf = fab {[def.material.kind] = {[def.material[def.material.kind]] = def.mass}} 44 + 45 +-- this is bugged: the same item can satisfy both e.g. metal.steel and element.fe 46 +-- if not (mf[class] and mf[class][x]) then 47 +-- mf = mf:elementalize() 48 + if not (mf[class] and mf[class][x]) then return 0 end 49 +-- end 50 + 51 + local perItem = mf[class][x] 52 + local wholeStack = perItem * stack:get_count() 53 + 54 + local deduct = ItemStack() 55 + local taken = 0 repeat 56 + taken = taken + perItem 57 + deduct:add_item(stack:take_item(1)) 58 + until taken >= n or stack:is_empty() 59 + return taken, deduct 60 + 61 + --[[ outsmarted myself with this one :/ 62 + local fab = def.recover or def.fab 63 + -- we ignore recover_vary bc this needs to be deterministic 64 + local function tryFab(fab) 65 + if not fab then return 0 end 66 + if fab[class] and fab[class][x] then 67 + local perItem = fab[class][x] 68 + local wholeStack = perItem * stack:get_count() 69 + print('fab has substance', n, perItem, wholeStack) 70 + local deduct = ItemStack() 71 + local taken = 0 repeat 72 + taken = taken + perItem 73 + deduct:add_item(stack:take_item(1)) 74 + until taken >= n 75 + return taken, deduct 76 + end 77 + return 0 78 + end 79 + local z,c = tryFab(fab) 80 + if z == 0 then -- does it work if we break down the constituent compounds? 81 + z,c = tryFab(fab:elementalize()) 82 + end]] 83 + end 84 +end 85 +local function fCanister(class) 86 + return function(x, n, stack) 87 + local amt, deduct = 0 88 + return amt, deduct 89 + end 90 +end 36 91 37 92 local fields = { 38 93 -- fabrication eligibility will be determined by which kinds 39 94 -- of input a particular fabricator can introduce. e.g. a 40 95 -- printer with a but no cache can only print items whose 41 96 -- recipe only names elements as ingredients 42 97 element = { 43 98 name = {"element", "elements"}; 44 99 string = function(x, n, long) 45 100 local el = starlit.world.material.element.db[x] 46 - return lib.math.si('g', n) .. ' ' .. ((not long and el.sym) or el.name) 101 + return lib.math.siUI('g', n) .. ' ' .. ((not long and el.sym) or el.name) 47 102 end; 48 103 image = function(x, n) 49 104 return string.format('starlit-element-%s.png', x) 50 105 end; 106 + inventory = fRawMat 'element'; 51 107 op = fQuant; 52 108 }; 53 109 metal ={ 54 110 name = {"metal", "metals"}; 55 111 string = function(x, n) 56 112 local met = starlit.world.material.metal.db[x] 57 - return lib.math.si('g', n) .. ' ' .. met.name 113 + return lib.math.siUI('g', n) .. ' ' .. met.name 58 114 end; 59 115 image = function(x, n) 60 116 local met = starlit.world.material.metal.db[x] 61 - return ItemStack(met.form.ingot):get_definition().inventory_image 117 + return ItemStack(met.form.brick):get_definition().inventory_image 62 118 end; 119 + inventory = fRawMat 'metal'; 63 120 op = fQuant; 64 121 }; 65 122 liquid = { 66 123 name = {"liquid", "liquids"}; 67 124 string = function(x, n) 68 125 local liq = starlit.world.material.liquid.db[x] 69 - return lib.math.si('L', n) .. ' ' .. liq.name 126 + return lib.math.siUI('L', n) .. ' ' .. liq.name 70 127 end; 128 + inventory = fCanister 'liquid'; 71 129 op = fQuant; 72 130 }; 73 131 gas = { 74 132 name = {"gas", "gasses"}; 75 133 string = function(x, n) 76 134 local gas = starlit.world.material.gas.db[x] 77 - return lib.math.si('g', n) .. ' ' .. gas.name 135 + return lib.math.siUI('g', n) .. ' ' .. gas.name 78 136 end; 137 + inventory = fCanister 'gas'; 79 138 op = fQuant; 80 139 }; 81 140 -- crystal = { 82 141 -- op = fQuant; 83 142 -- }; 84 143 item = { 85 144 name = {"item", "items"}; 86 145 string = function(x, n) 87 146 local i = minetest.registered_items[x] 88 147 return tostring(n) .. 'x ' .. i.short_description 89 148 end; 149 + image = function(x, n) 150 + return ItemStack(x):get_definition().inventory_image 151 + end; 152 + inventory = function(x, n, stack) 153 + x = ItemStack(x) 154 + if not x:equals(stack) then return nil end 155 + local deduct = stack:take_item(x:get_count() * n) 156 + return deduct:get_count(), deduct 157 + end; 90 158 }; 91 159 92 160 -- factors 93 161 94 - cost = {op=fFac}; -- units vary 162 + cost = { 163 + name = {"cost", "costs"}; 164 + op=fFac; -- units vary 165 + string = function(x,n) 166 + local units = { 167 + power = 'J'; 168 + } 169 + local s 170 + if units[x] then 171 + s = lib.math.siUI(units[x], n) 172 + elseif starlit.world.stats[x] then 173 + s = starlit.world.stats[x].desc(n) 174 + else 175 + s = tostring(n) 176 + end 177 + return string.format('%s: %s',x,s) 178 + end; 179 + image = function(x,n) 180 + local icons = { 181 + power = 'starlit-ui-icon-stat-power.png'; 182 + numina = 'starlit-ui-icon-stat-numina.png' 183 + } 184 + return icons[x] 185 + end; 186 + }; 95 187 time = {op=fFac}; -- (s) 96 188 -- print: base printing time 97 189 size = {op=fSize}; 98 190 -- printBay: size of the printer bay necessary to produce the item 99 191 req = {op=fReq}; 100 192 flag = {op=fFlag}; -- means that can be used to produce the item & misc flags 101 193 -- print: allow production with a printer 102 194 -- smelt: allow production with a smelter 103 195 -- all else defaults to underwrite 104 196 } 105 197 106 198 local order = { 107 - 'element', 'metal', 'liquid', 'gas', 'item' 199 + 'element', 'metal', 'liquid', 'gas', 'item', 200 + 'cost' 108 201 } 109 202 110 203 local lib = starlit.mod.lib 111 204 112 -local fab fab = lib.class { 205 +fab = lib.class { 113 206 __name = 'starlit:fab'; 114 207 115 208 fields = fields; 116 209 order = order; 117 210 construct = function(q) return q end; 118 211 __index = { 119 212 elementalize = function(self) 120 213 local e = fab {element = self.element or {}} 121 214 for _, kind in pairs {'metal', 'gas', 'liquid'} do 122 215 for m,mass in pairs(self[kind] or {}) do 123 - local mc = starlit.world.material[kind][m].composition 216 + local mc = starlit.world.material[kind].db[m].composition 124 217 e = e + mc:elementalize()*mass 125 218 end 126 219 end 127 220 return e 128 221 end; 129 222 130 223 elementSeq = function(self) ................................................................................ 204 297 if next(t) then table.insert(all, { 205 298 id=o, list=t; 206 299 header=fields[o].name[t[2] and 2 or 1]; 207 300 }) end 208 301 end 209 302 return all 210 303 end; 304 + seek = function(self, invs) 305 + local consumed = {} 306 + local spec = fab{item={}} -- used to generate a convenient visualization 307 + local unsatisfied = fab{} 308 + local cache = {} 309 + local leftover = fab{} 310 + local function alreadyGot(inv,slot) 311 + local already = cache[inv] and cache[inv][slot] and true 312 + if cache[inv] == nil then cache[inv] = {} end 313 + cache[inv][slot] = true 314 + return already 315 + end 316 + for ci, cat in ipairs(order) do 317 + local scan = fields[cat].inventory 318 + if scan and self[cat] then 319 + for substance, amt in pairs(self[cat]) do 320 +-- print('check substance', substance, amt, dump(self[cat])) 321 + local amtFound = 0 322 + local stacks = {} 323 + for ii, inv in ipairs(invs) do 324 +-- print(' - check inventory',ii,inv,'for',cat,substance,amt) 325 + for oi, o in ipairs(inv) do 326 +-- print(' - check stack', oi, o) 327 + local st = ItemStack(o) 328 + if not st:is_empty() then 329 + local avail, deduct = scan(substance,amt,st) 330 + if avail > 0 then 331 + amtFound = amtFound + avail 332 +-- print(' - found amt', amtFound,ii,oi) 333 + if not alreadyGot(ii,oi) then 334 + local sv = { 335 + inv=ii, slot=oi; 336 + consume=deduct, remain=st; 337 + satisfy=fab{[cat]={[substance]=avail}} 338 + } 339 + table.insert(stacks, sv) 340 + end 341 + if amtFound >= amt then goto suffice end 342 + end 343 + end 344 + end 345 + end 346 + 347 + ::insufficient:: do -- record the failure and move on 348 + if unsatisfied[cat] == nil then unsatisfied[cat] = {} end 349 + unsatisfied[cat][substance] = amt-amtFound 350 + end 351 + 352 + ::suffice:: -- commit the stack diff 353 + for si,sv in ipairs(stacks) do 354 +-- table.insert(consumed, sv) 355 + local di = ItemStack(sv.consume) 356 + local din = ItemStack(sv.consume):get_name() 357 + if not spec.item[din] then spec.item[din] = 0 end 358 + spec.item[din] = spec.item[din] + di:get_count() 359 + local lo = amtFound-amt if lo > 0 then 360 + leftover = leftover + fab{[cat]={[substance]=lo}} 361 + end 362 + end 363 + 364 + end 365 + end 366 + end 367 + return (next(unsatisfied) == nil), consumed, unsatisfied, leftover, spec 368 + end; 211 369 }; 212 370 213 371 __tostring = function(self) 214 372 local t = {} 215 373 for i,o in ipairs(order) do 216 374 if self[o] and fields[o].string then 217 375 for mat,amt in pairs(self[o]) do
Modified mods/starlit/init.lua from [d6e7e6c59c] to [aee56c43bb].
32 32 safe = 4; 33 33 overheat = 32; 34 34 boiling = 100; 35 35 thermalConductivity = 0.05; -- κ 36 36 }; 37 37 rad = { 38 38 }; 39 + 40 + phys = { 41 + --- HACK HACK HAAAAAAAAAAACK 42 + engineGravity = minetest.settings:get('movement_gravity') or 9.81 43 + }; 39 44 }; 40 45 41 46 activeUsers = { 42 47 -- map of username -> user object 43 48 }; 44 49 activeUI = { 45 50 -- map of username -> UI context ................................................................................ 272 277 273 278 starlit.include 'element' 274 279 275 280 starlit.include 'terrain' 276 281 starlit.include 'interfaces' 277 282 starlit.include 'suit' 278 283 279 -minetest.settings:set('movement_gravity', starlit.world.planet.gravity) -- ??? seriously??? 284 +-- minetest.settings:set('movement_gravity', starlit.world.planet.gravity) -- ??? seriously??? 285 +-- THIS OVERRIDES THE GLOBAL SETTING *AND PERSISTS IT* WHAT IN THE SATANIC FUCK 280 286 281 287 --------------- 282 288 -- callbacks -- 283 289 --------------- 284 290 -- here we connect our types up to the minetest API 285 291 286 292 local function userCB(fn)
Modified mods/starlit/interfaces.lua from [e3ed80cb5c] to [c1a1690c3b].
168 168 end 169 169 end 170 170 if not pgm then return false end -- HAX 171 171 172 172 -- kind=active programs must be assigned to a command slot 173 173 -- kind=direct programs must open their UI 174 174 -- kind=passive programs must toggle on and off 175 + local function suitCtx(pgm) 176 + local chips = user.entity:get_inventory():get_list 'starlit_suit_chips' 177 + local pgmctx = starlit.mod.electronics.chip.usableSoftware(chips, {pgm})[1] 178 + return { 179 + context = 'suit'; 180 + program = pgmctx; 181 + } 182 + end 183 + 175 184 if pgm.sw.powerKind == 'active' then 176 185 if cfg then 177 186 user:openUI(pgm.sw.ui, 'index', { 178 187 context = 'suit'; 179 188 program = pgm; 180 189 }) 181 190 return false ................................................................................ 189 198 elseif pptrMatch(ptr, pnan.secondary) then 190 199 pnan.secondary = nil 191 200 else 192 201 pnan.secondary = ptr 193 202 end 194 203 user:suitSound 'starlit-configure' 195 204 elseif pgm.sw.powerKind == 'direct' then 196 - local ctx = { 197 - context = 'suit'; 198 - program = pgm; 199 - } 205 + local ctx = suitCtx(pgm) 200 206 if pgm.sw.ui then 201 207 user:openUI(pgm.sw.ui, 'index', ctx) 202 208 return false 203 209 else 204 210 pgm.sw.run(user, ctx) 205 211 end 206 212 elseif pgm.sw.powerKind == 'passive' then 207 213 if cfg then 208 - user:openUI(pgm.sw.ui, 'index', { 209 - context = 'suit'; 210 - program = pgm; 211 - }) 214 + user:openUI(pgm.sw.ui, 'index', suitCtx(pgm)) 212 215 return false 213 216 end 214 217 215 218 local addDisableRec = true 216 219 for i, e in ipairs(pgm.file.body.conf) do 217 220 if e.key == 'disable' and e.value == 'yes' then 218 221 addDisableRec = false ................................................................................ 326 329 w=2, h=2; 327 330 }) 328 331 menu.padding = 1; 329 332 end 330 333 return starlit.ui.build(menu) 331 334 end; 332 335 }; 333 - compilerListRecipes = { 334 - }; 335 336 psi = { 336 337 render = function(state, user) 337 338 return starlit.ui.build { 338 339 kind = 'vert', mode = 'sw'; 339 340 padding = 0.5; 340 341 } 341 342 end; ................................................................................ 346 347 local tb = { 347 348 kind = 'vert', mode = 'sw'; 348 349 padding = 0.5, 349 350 {kind = 'hztl', padding = 0.25; 350 351 {kind = 'label', text = 'Name', w = 2, h = barh}; 351 352 {kind = 'label', text = user.persona.name, w = 4, h = barh}}; 352 353 } 353 - local statBars = {'nutrition', 'hydration', 'fatigue', 'morale', 'irradiation', 'illness'} 354 - for idx, id in ipairs(statBars) do 355 - local s = starlit.world.stats[id] 356 - local amt, sv = user:effectiveStat(id) 357 - local min, max = starlit.world.species.statRange(user.persona.species, user.persona.speciesVariant, id) 354 + local statBars = {'stamina', 'numina', 'nutrition', 'hydration', 'fatigue', 'morale', 'irradiation', 'illness'} 355 + local function wrapElts(n, l) 356 + local all = {kind='vert'} 357 + local ct, row 358 + local function flush() 359 + if row then 360 + table.insert(all, row) 361 + end 362 + row = {kind='hztl', spacing = 0.2} 363 + ct = 0 364 + end 365 + flush() 366 + for i, e in ipairs(l) do 367 + ct = ct + 1 368 + table.insert(row, e) 369 + if ct >= n then flush() end 370 + end 371 + flush() 372 + return all 373 + end 374 + local bars = {} 375 + local function pushBar(s, amt, sv, min, max) 358 376 local st = string.format('%s / %s', s.desc(amt, true), s.desc(max)) 359 - table.insert(tb, {kind = 'hztl', padding = 0.25; 377 + table.insert(bars, {kind = 'hztl', padding = 0.25; 360 378 {kind = 'label', w=2, h=barh, text = lib.str.capitalize(s.name)}; 361 379 {kind = 'hbar', w=4, h=barh, fac = sv, text = st, color=s.color}; 362 380 }) 363 381 end 382 + do local hp, hpf = user:effectiveStat 'health' 383 + local desc = { 384 + name='health'; 385 + desc = function(hp) return tostring(hp) end; 386 + color = {hue=10,sat=1,lum=.5}; 387 + } 388 + pushBar(desc, hp, hpf, starlit.world.species.statRange(user.persona.species, user.persona.speciesVariant, 'health')) 389 + end 390 + do local ep, ex = user:suitCharge(), user:suitPowerCapacity() 391 + local desc = { 392 + name = 'power'; 393 + desc = function(j) return lib.math.siUI('J', j) end; 394 + color = {hue=190,sat=1,lum=.5}; 395 + } 396 + pushBar(desc, ep, ep/ex, 0, ex) 397 + end 398 + for idx, id in ipairs(statBars) do 399 + local s = starlit.world.stats[id] 400 + local amt, sv = user:effectiveStat(id) 401 + local min, max = starlit.world.species.statRange(user.persona.species, user.persona.speciesVariant, id) 402 + pushBar(s, amt, sv, min, max) 403 + end 404 + table.insert(tb, wrapElts(2, bars)) 364 405 local abilities = { 365 406 maneuver = {}; 366 407 direct = {}; 367 408 passive = {}; 368 409 } 369 410 state.abilityMap = {} 370 411 for i, a in pairs(user:species().abilities) do ................................................................................ 458 499 user:suitPowerStateSet(suitMode) 459 500 return true 460 501 end 461 502 end; 462 503 }; 463 504 }; 464 505 }) 506 + 507 +local function compilerCanPrint(user, cpl, scm) 508 + local output = ItemStack(scm.sw.output):get_definition() 509 + local fab = output._starlit.fab 510 + local sw = scm.sw 511 + local ok, consume, unsat, leftover, itemSpec = fab:seek { 512 + user.entity:get_inventory():get_list 'main'; 513 + } 514 + 515 + local cost = { 516 + consume = consume, unsat = unsat, leftover = leftover, itemSpec = itemSpec; 517 + runtimeEstimate = scm.speed + cpl.speed + (fab.time and fab.time.print or 0); 518 + power = cpl.powerCost + scm.powerCost; 519 + ram = (cpl.cost and cpl.cost.ram or 0) 520 + + (scm.cost and scm.cost.ram or 0); 521 + cycles = (cpl.cost and cpl.cost.cycles or 0) 522 + + (scm.cost and scm.cost.cycles or 0); 523 + } 524 + 525 + local userComp = starlit.mod.electronics.chip.sumCompute( 526 + user.entity:get_inventory():get_list 'starlit_suit_chips' 527 + ) 528 + 529 + if ok and cost.power <= user:suitCharge() and cost.ram <= userComp.ram then 530 + return true, cost 531 + else return false, cost end 532 +end 465 533 466 534 -- TODO destroy suit interfaces when power runs out or suit/chip is otherwise disabled 467 535 starlit.interface.install(starlit.type.ui { 468 536 id = 'starlit:compile-matter-component'; 469 537 sub = { 470 538 suit = function(state, user, evt) 471 539 if evt.kind == 'disrobe' then state:close() ................................................................................ 480 548 setupState = function(state, user, ctx) 481 549 state.pgm = ctx.program 482 550 state.select = {} 483 551 local E = starlit.mod.electronics 484 552 if ctx.context == 'suit' then 485 553 state.fetch = function() 486 554 local cst = user.entity:get_inventory():get_list 'starlit_suit_chips' 487 - local cl = {order={}, map={}} 555 + local cl = {order={}, map={}, slot={}} 488 556 for i, c in ipairs(cst) do 489 557 if not c:is_empty() then 490 558 local d = E.chip.read(c) 491 559 local co = { 492 560 stack = c; 493 561 data = d; 494 562 } 495 563 table.insert(cl.order, co) 496 564 cl.map[d.uuid] = co 565 + cl.slot[i] = co 497 566 end 498 567 end 499 - if state.select.chip and not cl.map[state.select.chip.data.uuid] then 500 - -- chip no longer available 568 + 569 + -- kill me fam 570 + if ( state.select.chip 571 + and state.select.chip ~= true 572 + and not cl.map[state.select.chip]) 573 + or (state.select.scm 574 + and not state.select.scms[state.select.scm]) 575 + then 576 + -- chip or pgm no longer available 501 577 user:suitSound 'starlit-error' 502 578 state.select = {} 503 579 end 504 580 state.select.chips = cl 505 581 506 582 state.select.scms = {} 507 583 if state.select.chip then 508 - state.select.scms = E.chip.usableSoftware({state.select.chip.stack},nil, 509 - function(s) return s.sw.kind == 'schematic' end) 584 + state.select.scms = E.chip.usableSoftware(cst,nil, function(s) 585 + if state.select.chip ~= true then 586 + if cl.slot[s.chipSlot].data.uuid ~= state.select.chip then 587 + return false 588 + end 589 + end 590 + return s.sw.kind == 'schematic' 591 + end) 510 592 end 593 + 511 594 end 512 595 end 513 596 end; 514 597 515 598 onClose = function(state, user) 516 599 user:suitSound 'starlit-quit' 517 600 end; ................................................................................ 518 601 handle = function(state, user, q) 519 602 local sel = state.select 520 603 state.fetch() 521 604 local chips = state.select.chips 522 605 local function chirp() 523 606 user:suitSound 'starlit-nav' 524 607 end 525 - local function onPickChip(chip) 526 - chirp() 527 - sel.chip = chip 528 - return true 529 - end 530 - local function onPickScm(scm) 531 - chirp() 532 - sel.scm = scm 533 - return true 608 + 609 + local function trySelection(id) 610 + if sel[id] == nil then 611 + for k in next, q do 612 + local pat = "^"..id.."_(%d+)$" -- ew 613 + local idx = k:match(pat) 614 + if idx then 615 + local cm = tonumber(idx) 616 + if cm then 617 + chirp() 618 + sel[id] = cm 619 + return true 620 + end 621 + end 622 + end 623 + end 534 624 end 535 625 536 626 if sel.chip == nil then 537 - for k in next, q do 538 - local id = k:match "^chip_(%d+)$" 539 - if id then 540 - local cm = chips.map[tonumber(id)] 541 - if cm then return onPickChip(cm) end 542 - end 627 + if q.showAll then 628 + chirp() 629 + sel.chip = true 630 + return true 631 + elseif q.find then 632 + chirp() 633 + -- TODO 634 + return true 543 635 end 544 - elseif sel.scm == nil then 545 - if q.back then chirp() sel.chip = nil return true end 546 - for k in next, q do 547 - local id = k:match "^scm_(%d+)$" 548 - if id then 549 - local cm = state.select.scms[tonumber(id)] 550 - if cm then return onPickScm(cm) end 636 + end 637 + 638 + if trySelection('chip') then 639 + return true 640 + elseif trySelection('scm') then 641 + return true 642 + else 643 + if q.back then 644 + chirp() 645 + if sel.input then 646 + sel.input = nil 647 + elseif sel.scm then 648 + sel.scm = nil 649 + elseif sel.chip then 650 + sel.chip = nil 651 + end 652 + return true 653 + elseif q.commit then 654 + if not sel.input then 655 + chirp() 656 + sel.input = true 657 + return true 658 + else 659 + local scm = sel.scms[sel.scm] 660 + local ok, cost = compilerCanPrint(user, state.pgm, scm) 661 + if ok then 662 + user:suitSound 'starlit-configure' 663 + -- consume consumables 664 + -- add print job 665 + state.select = {} 666 + return true 667 + else 668 + user:suitSound 'starlit-error' 669 + end 551 670 end 552 671 end 553 - else 554 - if q.back then chirp() sel.scm = nil return true end 555 672 end 673 + 556 674 end; 557 675 558 676 render = function(state, user) 559 677 local sel, pgmSelector = state.select, {} 560 678 state.fetch() 561 679 562 680 local function pushSelector(id, item, label, desc, req) 563 681 local rh = .5 564 682 local label = {kind = 'text', w = 10-1.5, h=1.5; 565 - text = '<global valign=middle>'..label } 683 + text = '<global valign=middle>'..lib.str.htsan(label) } 566 684 if req then 567 685 label.h = label.h - rh - .2 568 686 569 687 local imgs = {} 570 688 for ci,c in ipairs(req) do 571 689 for ei, e in ipairs(c.list) do 572 690 table.insert(imgs, {kind = 'img', w=rh, h=rh, img=e.img}) ................................................................................ 591 709 if sel.chips == nil then 592 710 table.insert(pgmSelector, {kind = 'img', img = 'starlit-ui-alert.png', w=2, h=2}) 593 711 elseif sel.chip == nil then 594 712 for i, c in ipairs(sel.chips.order) do 595 713 -- TODO filter out chips without schematics? 596 714 pushSelector('chip_' .. c.data.uuid, c.stack, c.data.label) 597 715 end 716 + if next(sel.chips.order) then 717 + table.insert(pgmSelector, {kind = 'hztl', w=10,h=1.5; 718 + {kind = 'button', w=5,h=1.5; id='showAll', label='Show All'}; 719 + {kind = 'button', w=5,h=1.5; id='find', label='Find'}; 720 + }) 721 + end 598 722 else 599 723 if sel.scm == nil then 600 724 for idx, ent in ipairs(sel.scms) do 601 725 local fab = ItemStack(ent.sw.output):get_definition()._starlit.fab 602 726 if fab.flag.print then 603 727 local req = fab:visualize() 604 728 pushSelector('scm_' .. idx, ent.sw.output, ent.sw.name, nil, req) 605 729 end 606 730 end 607 731 table.insert(pgmSelector, back) 608 732 else 609 - local output = ItemStack(sel.scm.sw.output):get_definition() 733 + local scm = sel.scms[sel.scm] 734 + local output = ItemStack(scm.sw.output):get_definition() 610 735 local fab = output._starlit.fab 611 - local sw = sel.scm.sw 736 + local sw = scm.sw 737 + local function unmet(str) 738 + return lib.color(1,.3,.3):fmt(str) 739 + end 612 740 table.insert(pgmSelector, {kind = 'hztl', w=10, h=1.2; 613 741 {kind = 'img', item = sw.output, w=1.2, h=1.2, desc=output.description}; 614 - {kind = 'text', text = string.format('<global valign=middle><b>%s</b>', sw.name), w=10-1.2,h=1.2}; 742 + {kind = 'text', text = string.format('<global valign=middle><b>%s</b>', lib.str.htsan(sw.name)), w=10-1.2,h=1.2}; 615 743 }) 616 744 local inputTbl = {kind = 'vert', w=5,h=0; 617 - {kind = 'hbar', w=5, h=.5, text='Input'}}; 618 - local costTbl = {kind = 'vert', w=5,h=0; spacing=.25; 619 - {kind = 'hbar', w=5, h=.5, text='Process'}}; 745 + {kind = 'hbar', w=5, h=.5, text=sel.input and 'Input Plan' or 'Input'}}; 746 + local costTbl = {kind = 'vert', w=5,h=0; 747 + {kind = 'hbar', w=5, h=.5, text=sel.input and 'Process Plan' or 'Process'}}; 620 748 local reqPane = {kind = 'pane', id='reqPane', w=10, h=7; 621 749 {kind = 'hztl', w=10,h=0; inputTbl, costTbl} 622 750 } 623 - local req = fab:visualize() 624 - for ci,c in ipairs(req) do 625 - table.insert(inputTbl, {kind = 'label', w=4.5, h=1, x=.5; 626 - text=lib.str.capitalize(c.header)}); 627 - for ei,e in ipairs(c.list) do 628 - table.insert(inputTbl, {kind = 'hztl', w=4, h=.5, x=1; 629 - {kind='img', w=.5,h=.5, img=e.img}; 630 - {kind='label', w=3.3,h=.5,x=.2, text=e.label}; 631 - }); 751 + local function pushCost(x, t, val) 752 + table.insert(costTbl, {kind='label', w=4.5,h=.5,x=x; 753 + text=string.format('%s: %s',t,val); 754 + }) 755 + end 756 + local function pushComputeCosts(header, p) 757 + if p then 758 + table.insert(costTbl, {kind = 'label', w=5, h=.5, x=0; text=header}); 759 + if p.cycles then 760 + pushCost(.5, 'Compute', lib.math.siUI({'cycle','cycles'}, p.cycles, true)) 761 + end 762 + if p.power then 763 + local str = lib.math.siUI('J', p.power) 764 + if p.power > user:suitCharge() then str = unmet(str) end 765 + pushCost(.5, 'Power', str) 766 + end 767 + if p.ram then 768 + local str = string.format("%s / %s", 769 + lib.math.siUI('B', p.ram), 770 + lib.math.siUI('B', state.pgm.comp.ram)) 771 + if p.ram > state.pgm.comp.ram then str = unmet(str) end 772 + pushCost(.5, 'Memory', str) 773 + end 774 + end 775 + end 776 + 777 + local function fabToUI(x, inputTbl, req) 778 + for ci,c in ipairs(req) do 779 + table.insert(inputTbl, {kind = 'label', w=5-x, h=.5, x=x; 780 + text=lib.str.capitalize(c.header)}); 781 + for ei,e in ipairs(c.list) do 782 + table.insert(inputTbl, {kind = 'hztl', w=4.5-x, h=.5, x=x+.5; 783 + {kind='img', w=.5,h=.5, img=e.img}; 784 + {kind='label', w=3.3,h=.5,x=.2, text=lib.str.capitalize(e.label)}; 785 + }); 786 + end 632 787 end 633 788 end 634 - if sw.cost then 635 - local function pushCost(t, val) 636 - table.insert(costTbl, {kind='text', w=4.5,h=.5,x=.5; 637 - text=string.format('<b>%s</b>: %s',t,val); 638 - }) 789 + 790 + local commitHue=120, commitLabel 791 + if not sel.input then 792 + commitLabel = 'Plan' 793 + fabToUI(0, inputTbl, fab:visualize()) 794 + local function pushComputeCostsSw(header, p) 795 + if p.sw.cost then 796 + pushComputeCosts(header, { 797 + cycles = p.sw.cost.cycles; 798 + power = p.powerCost; 799 + ram = p.sw.cost.ram; 800 + }) 801 + end 802 + end 803 + pushComputeCostsSw('Schematic', scm) 804 + pushComputeCostsSw('Compiler', state.pgm) 805 + else 806 + commitLabel = 'Commit' 807 + pushComputeCosts('Total', { 808 + cycles = (scm.sw.cost and scm.sw.cost.cycles or 0) 809 + + (state.pgm.sw.cost and state.pgm.sw.cost.cycles or 0); 810 + power = (scm.powerCost or 0) 811 + + (state.pgm.powerCost or 0) 812 + + (fab.cost and fab.cost.power or 0); 813 + ram = (scm.sw.cost and scm.sw.cost.ram or 0) 814 + + (state.pgm.sw.cost and state.pgm.sw.cost.ram or 0); 815 + }) 816 + if fab.time and fab.time.print then 817 + pushCost(0, 'Job Runtime', lib.math.timespec(fab.time.print + scm.speed)) 818 + pushCost(.5, 'Print Time', lib.math.timespec(fab.time.print)) 819 + pushCost(.5, 'CPU Time', lib.math.timespec(scm.speed + state.pgm.speed)) 820 + end 821 + local ok, compileCost = compilerCanPrint(user, state.pgm, scm) 822 + fabToUI(0, inputTbl, compileCost.itemSpec:visualize()) 823 + 824 + if next(compileCost.unsat) then 825 + local vis = compileCost.unsat:visualize() 826 + for si, s in ipairs(vis) do 827 + s.header = 'Missing ' .. s.header 828 + for ei, e in ipairs(s.list) do 829 + e.label = lib.color(1,.2,.2):fmt(e.label) 830 + end 831 + end 832 + fabToUI(0, inputTbl, vis) 639 833 end 640 - if sw.cost.cycles then 641 - pushCost('Energy', lib.math.siUI('J', sel.scm.powerCost)) 642 - pushCost('Compute', lib.math.siUI({'cycle','cycles'}, sw.cost.cycles, true)) 643 - end 834 + if not ok then commitHue = 0 end 644 835 end 645 836 table.insert(pgmSelector, reqPane) 646 837 table.insert(pgmSelector, {kind = 'hztl', w=10,h=1.2; 647 - {kind = 'button', id='back', label = '<- Back', w=5,h=1.2}; 648 - {kind = 'button', id='print', label = 'Print ->', w=5,h=1.2, color={hue=120,sat=0,lum=0}}; 838 + {kind = 'button', id='back', label = '← Back', w=5,h=1.2}; 839 + {kind = 'button', id='commit', label = commitLabel .. ' →', w=5,h=1.2, color={hue=commitHue,sat=0,lum=0}}; 649 840 }) 650 841 end 651 842 end 652 843 653 844 return starlit.ui.build { 654 845 kind = 'hztl', padding = 0.5; w = 20, h = 10, mode = 'sw'; 655 846 {kind = 'vert', w = 5, h = 5;
Modified mods/starlit/species.lua from [34f8558850] to [e0959a01e2].
90 90 local invis = lib.image '[fill:1x1:0,0:#00000000' 91 91 local plate = adorn.suit and adorn.suit.plate or invis 92 92 local lining = adorn.suit and adorn.suit.lining or invis 93 93 94 94 return {lining, plate, skin, skin, eye, hair} 95 95 end; 96 96 stats = { 97 - psi = 1.2; 97 + numina = 1.2; 98 98 nutrition = .8; -- women have smaller stomachs 99 99 hydration = .8; 100 100 morale = 0.8; -- you are not She-Bear Grylls 101 101 irradiation = 0.8; -- you are smaller, so it takes less rads to kill ya 102 102 }; 103 103 traits = { 104 104 health = 400; ................................................................................ 105 105 lungCapacity = .6; 106 106 sturdiness = 0; -- women are more fragile and thus susceptible to blunt force trauma 107 107 metabolism = .150; -- kCal/s 108 108 painTolerance = 0.4; 109 109 dehydration = 10e-4; -- L/s 110 110 speed = 1.1; 111 111 staminaRegen = 10.0; 112 - psiRegen = 0.05; -- ψ/s 113 - psiPower = 1.2; 112 + numinaRegen = 0.05; -- ψ/s 113 + psi = 1.2; 114 114 }; 115 115 }; 116 116 male = { 117 117 name = 'Human Male'; 118 118 eyeHeight = 1.6; 119 119 stats = { 120 - psi = 1.0; 120 + numina = 1.0; 121 121 nutrition = 1.0; 122 122 hydration = 1.0; 123 123 staminaRegen = 7; -- men are strong but have inferior endurance 124 124 }; 125 125 traits = { 126 126 health = 500; 127 127 painTolerance = 1.0; 128 128 lungCapacity = 1.0; 129 129 sturdiness = 0.3; 130 130 metabolism = .150; -- kCal/s 131 131 dehydration = 15e-4; -- L/s 132 132 speed = 1.0; 133 - psiRegen = 0.025; 134 - psiPower = 1.0; 133 + numinaRegen = 0.025; 134 + psi = 1.0; 135 135 }; 136 136 }; 137 137 }; 138 138 traits = {}; 139 139 abilities = {bioAbilities.sprint}; 140 140 }; 141 141 } ................................................................................ 232 232 local min, max = starlit.world.species.statRange(pSpecies, pVariant, st) 233 233 local delta = max - min 234 234 return min + delta*p 235 235 end 236 236 local ps = starlit.world.species.mkPersonaFor(pSpecies,pVariant) 237 237 local startingHP = pct('health', 1.0) 238 238 if circumstances.injured then startingHP = pct('health', circumstances.injured) end 239 - if circumstances.psiCharged then ps.statDeltas.psi = pct('psi', circumstances.psiCharged) end 239 + if circumstances.numinaCharged then ps.statDeltas.numina = pct('numina', circumstances.numinaCharged) end 240 240 for k,v in pairs(starlit.world.stats) do ps.statDeltas[k] = 0 end 241 241 ps.statDeltas.warmth = 20 -- don't instantly start dying of frostbite 242 242 ps.statDeltas.nutrition = 2000 -- shoulda packed more MRE :c 243 243 ps.statDeltas.hydration = 3 -- stay hydrated uwu 244 244 245 245 entity:set_properties{hp_max = var.traits.health or sp.traits.health} 246 246 entity:set_hp(startingHP, 'initial hp')
Modified mods/starlit/stats.lua from [0688acc2a6] to [9558da3e0c].
18 18 end 19 19 end 20 20 21 21 local function C(h, s, l) 22 22 return lib.color {hue = h, sat = s or 1, lum = l or .7} 23 23 end 24 24 starlit.world.stats = { 25 - psi = {min = 0, max = 500, base = 0, desc = U('ψ', 1), color = C(320), name = 'numina', srzType = T.decimal}; 25 + numina = {min = 0, max = 500, base = 0, desc = U('ψ', 1), color = C(320), name = 'numina', srzType = T.decimal}; 26 26 -- numina is measured in ψ 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', harm=true, srzType = T.decimal}; 29 + fatigue = {min = 0, max = 76 * 60, base = 0, desc = U('hr', 60, true), color = C(288,1,.8), name = 'fatigue', harm=true, srzType = T.decimal}; 30 30 -- fatigue is measured in minutes one needs to sleep to cure it 31 - stamina = {min = 0, max = 10 * 20, base = true, desc = U('m', 100), color = C(88), name = 'stamina'}; 31 + stamina = {min = 0, max = 10 * 20, base = true, desc = U('m', 10), color = C(88), name = 'stamina'}; 32 32 -- stamina is measured in how many 10th-nodes (== cm) one can sprint 33 - nutrition = {min = 0, max = 8000, base = 0, desc = U('kCal', 1, true), color = C(43,.5,.4), name = 'nutrition', srzType = T.decimal}; 33 + nutrition = {min = 0, max = 8000, base = 0, desc = U('kCal', 1, true), color = C(43,1,.8), name = 'nutrition', srzType = T.decimal}; 34 34 -- hunger is measured in kcalories one must consume to cure it. at 0, you start dying 35 - hydration = {min = 0, max = 4, base = 0, desc = U('L', 1), color = C(217, .25,.4), name = 'hydration', srzType = T.decimal}; 35 + hydration = {min = 0, max = 4, base = 0, desc = U('L', 1), color = C(217), name = 'hydration', srzType = T.decimal}; 36 36 -- thirst is measured in L of H²O required to cure it 37 37 morale = {min = 0, max = 10 * 24 * 60, base = true, color = C(0,0,.8), name = 'morale', srzType = T.decimal; 38 38 desc = function(amt, excU) return lib.math.timespec(amt) end}; 39 39 -- morale is measured in minutes. e.g. at base rate morale degrades by 40 40 -- 60 points every hour. morale can last up to 10 earthdays 41 41 irradiation = {min = 0, max = 10, base = 0, desc = U('Gy', 1), color = C(141,1,.5), name = 'irradiation', harm=true, srzType = T.decimal}; 42 42 -- irrad is measured is milligreys ................................................................................ 50 50 -- illness is increased by certain conditions, and decreases on its own as your 51 51 -- body heals when those conditions wear off. some drugs can lower accumulated illness 52 52 -- but illness-causing conditions require specific cures 53 53 -- illness also causes thirst and fatigue to increase proportionately 54 54 } 55 55 56 56 starlit.world.statOrder = { 57 - 'health', 'stamina', 'psi', 'warmth'; 57 + 'health', 'stamina', 'numina', 'warmth'; 58 58 59 59 'nutrition', 'hydration', 'irradiation'; 60 60 'illness', 'morale', 'fatigue'; 61 61 } 62 62 63 63 local impactStruct = G.struct { 64 64 base = G.array(8, G.struct {id = T.str, val = T.decimal});
Modified mods/starlit/suit.lua from [7f11ba51a8] to [8324bad06e].
341 341 if rst.itemClass and not grp(item, rst.itemClass) then 342 342 return false 343 343 end 344 344 if rst.maintenanceNode then return false end 345 345 -- FIXME figure out best way to identify when the player is using a maintenance node 346 346 347 347 if grp(item, 'specialInventory') then 348 - if grp(item, 'powder') and list ~= 'starlit_suit_elem' then return false end 349 - -- FIXME handle containers 350 - if grp(item, 'psi') and list ~= 'starlit_psi' then return false end 351 348 end 352 349 353 350 return true 354 351 end 355 352 local function itemCanLeave(item, list) 356 353 local rst, ok = checkBaseRestrictions(list) 357 354 if not ok then return false end
Modified mods/starlit/ui.lua from [81aedb85b1] to [08cb8bbbbd].
249 249 if def.kind == 'hbar' 250 250 then wfac = wfac * clamp 251 251 else hfac = hfac * clamp 252 252 end 253 253 local x,y, w,h = state.x, state.y, def.w, def.h 254 254 widget('box[%s,%s;%s,%s;%s]', 255 255 x,y, w,h, cl:brighten(0.2):hex()) 256 - widget('box[%s,%s;%s,%s;%s]', 257 - x, y + (h*(1-hfac)), w * wfac, h * hfac, cl:hex()) 256 + if clamp > 0 then 257 + widget('box[%s,%s;%s,%s;%s]', 258 + x, y + (h*(1-hfac)), w * wfac, h * hfac, cl:hex()) 259 + end 258 260 if def.text then 259 261 widget('hypertext[%s,%s;%s,%s;;%s]', 260 262 state.x, state.y, def.w, def.h, 261 263 string.format('<global halign=center valign=middle color=%s>%s', fg:hex(), E(def.text))) 262 264 end 263 265 end 264 266
Modified mods/starlit/user.lua from [b2784a81d4] to [c928629a64].
19 19 persona = { 20 20 key = 'starlit:persona'; 21 21 type = starlit.store.persona; 22 22 }; 23 23 } 24 24 25 25 local suitStore = starlit.store.suitMeta 26 + 27 +local leds = { 28 + freeze = { 29 + icon = lib.image('starlit-ui-alert-temp-cold.png'); 30 + bg = lib.image('starlit-ui-alert-bg-temp-cold.png'); 31 + side = 'left'; 32 + }; 33 + overheat = { 34 + icon = lib.image('starlit-ui-alert-temp-hot.png'); 35 + bg = lib.image('starlit-ui-alert-bg-temp-hot.png'); 36 + side = 'left'; 37 + }; 38 + hydration = { 39 + icon = lib.image('starlit-ui-alert-hydration.png'); 40 + bg = lib.image('starlit-ui-alert-bg-hydration.png'); 41 + side = 'left'; 42 + }; 43 + nutrition = { 44 + icon = lib.image('starlit-ui-alert-nutrition.png'); 45 + bg = lib.image('starlit-ui-alert-bg-nutrition.png'); 46 + side = 'left'; 47 + }; 48 + 49 + radiation = { 50 + icon = lib.image('starlit-ui-alert-rad.png'); 51 + bg = lib.image('starlit-ui-alert-bg-rad.png'); 52 + side = 'right'; 53 + }; 54 + fatigue = { 55 + icon = lib.image('starlit-ui-alert-fatigue.png'); 56 + bg = lib.image('starlit-ui-alert-bg-fatigue.png'); 57 + side = 'right'; 58 + }; 59 +} 26 60 27 61 starlit.type.user = lib.class { 28 62 name = 'starlit:user'; 63 + leds = leds; 29 64 construct = function(ident) 30 65 local name, luser 31 66 if type(ident) == 'string' then 32 67 name = ident 33 68 luser = minetest.get_player_by_name(name) 34 69 else 35 70 luser = ident ................................................................................ 38 73 return { 39 74 entity = luser; 40 75 name = name; 41 76 hud = { 42 77 elt = {}; 43 78 bar = {}; 44 79 alarm = {}; 80 + led = { left={}, right={}, map={} }; 45 81 }; 46 82 tree = {}; 47 83 action = { 48 84 bits = 0; -- for control deltas 49 85 prog = {}; -- for recording action progress on a node; reset on refocus 50 86 tgt = {type='nothing'}; 51 87 sfx = {}; ................................................................................ 69 105 } 70 106 end; 71 107 __index = { 72 108 -------------- 73 109 -- overlays -- 74 110 -------------- 75 111 updateOverlays = function(self) 112 + -- minetest: because fuck you, that's why 113 + local engineGravity = starlit.constant.phys.engineGravity 114 + local targetGravity = starlit.world.planet.gravity 76 115 local phys = { 77 116 speed = self.pheno:trait('speed',1); 78 117 jump = self.pheno:trait('jump',1); 79 - gravity = 1; 118 + gravity = targetGravity / engineGravity; 80 119 speed_climb = 1; 81 120 speed_crouch = 1; 82 121 speed_walk = 1; 83 122 acceleration_default = 1; 84 123 acceleration_air = 1; 85 124 } 86 125 for i, o in ipairs(self.overlays) do o(phys) end ................................................................................ 372 411 self.hud.elt.bat = self:attachStatBar { 373 412 name = 'battery', stat = batteryLookup; 374 413 color = C(190,0,.2), size = 100; 375 414 pos = {x=0.5, y=1}, ofs = {x = hbofs - 4, y=-48 - bpad}; 376 415 dir = 0; 377 416 align = {x=1, y=-1}; 378 417 } 379 - self.hud.elt.psi = attachBasicStat { 380 - name = 'psi', stat = 'psi'; 418 + self.hud.elt.numina = attachBasicStat { 419 + name = 'numina', stat = 'numina'; 381 420 color = C(320,0,.2), size = 100; 382 421 pos = {x=0.5, y=1}, ofs = {x = hbofs - 4, y=-24 - bpad}; 383 422 dir = 0; 384 423 align = {x=1, y=-1}; 385 424 } 386 425 self.hud.elt.time = self:attachTextBox { 387 426 name = 'time'; ................................................................................ 477 516 self.entity:hud_remove(e.id) 478 517 end 479 518 end; 480 519 updateHUD = function(self) 481 520 for name, e in pairs(self.hud.elt) do 482 521 if e.update then e.update() end 483 522 end 523 + self:updateLEDs() 524 + end; 525 + updateLEDs = function(self) 526 + local time = minetest.get_gametime() 527 + local function updateSide(name, ofs, tx) 528 + local del = {} 529 + for i, l in ipairs(self.hud.led[name]) do 530 + local idx = 0 531 + if time - l.origin > 3 then 532 + if l.elt then self.entity:hud_remove(l.elt.id) end 533 + self.hud.led.map[l.kind] = nil 534 + table.insert(del, i) 535 + else 536 + local xc = (idx*48 + 400)*ofs 537 + if l.elt and next(del) then 538 + l.elt:update('offset', {x=xc, y=1}) 539 + else 540 + local tex = leds[l.kind].icon:blit(hudAdjustBacklight(leds[l.kind].bg)) 541 + if tx then tex = tex:transform(tx) end 542 + if not l.elt then 543 + l.elt = self:attachImage { 544 + tex = tex:render(); 545 + align = {x=ofs, y=-1}; 546 + pos = {x=.5, y=1}; 547 + scale = {x=1,y=1}; 548 + ofs = {x=xc, y=0}; 549 + } 550 + end 551 + end 552 + idx = idx + 1 553 + end 554 + end 555 + for _, i in ipairs(del) do 556 + table.remove(self.hud.led[name], i) 557 + end 558 + 559 + end 560 + updateSide('left', -1) 561 + updateSide('right', 1, 'FX') 484 562 end; 485 563 486 564 --------------------- 487 565 -- actions & modes -- 488 566 --------------------- 489 567 onModeChange = function(self, oldMode, silent) 490 568 self.hud.elt.crosshair.update() ................................................................................ 920 998 if run then 921 999 run(self, ctx) 922 1000 return true 923 1001 end 924 1002 return false 925 1003 end; 926 1004 927 - alarm = function(self, urgency, kind, freq, where) 1005 + alarm = function(self, urgency, kind, minFreq) 1006 + minFreq = minFreq or 1.5 1007 + local time = minetest.get_gametime() 1008 + local led = leds[kind] 1009 + 1010 + local ul = self.hud.led.map[kind] 1011 + if ul then 1012 + if time - ul.origin > minFreq then 1013 + ul.origin = time 1014 + else return end 1015 + end 1016 + 1017 + if urgency > 0 then 1018 + local urgencies = { 1019 + [1] = {sound = 'starlit-alarm'}; 1020 + [2] = {sound = 'starlit-alarm-urgent'}; 1021 + } 1022 + local urg = urgencies[urgency] or urgencies[#urgencies] 1023 + 1024 + if time - self.cooldownTimes.alarm > 1.5 then 1025 + self.cooldownTimes.alarm = time 1026 + self:suitSound(urg.sound) 1027 + end 1028 + end 1029 + 1030 + 1031 + local newLed = { 1032 + kind = kind; 1033 + origin = time; 1034 + } 1035 + self.hud.led.map[kind] = newLed 1036 + table.insert(self.hud.led[led.side], newLed) 1037 + 1038 + 1039 + self:updateLEDs() 1040 + 1041 + --[[ 928 1042 freq = freq or 3 929 1043 local urgencies = { 930 1044 [1] = {sound = 'starlit-alarm'}; 931 1045 [2] = {sound = 'starlit-alarm-urgent'}; 932 1046 } 933 1047 local gt = minetest.get_gametime() 934 1048 local urg = urgencies[urgency] or urgencies[#urgencies] ................................................................................ 954 1068 -- HATE. HATE. HAAAAAAAAAAATE 955 1069 minetest.after(freq/2, function() 956 1070 for k,v in pairs(self.hud.alarm) do 957 1071 self.entity:hud_remove(v.id) 958 1072 end 959 1073 self.hud.alarm={} 960 1074 end) 961 - end 1075 + end]] 962 1076 end; 963 1077 964 1078 ------------- 965 1079 -- weather -- 966 1080 ------------- 967 1081 updateWeather = function(self) 968 1082 end; ................................................................................ 1015 1129 }; 1016 1130 } 1017 1131 1018 1132 local clockInterval = 1.0 1019 1133 starlit.startJob('starlit:clock', clockInterval, function(delta) 1020 1134 for id, u in pairs(starlit.activeUsers) do 1021 1135 u.hud.elt.time:update() 1136 + u:updateLEDs() 1022 1137 end 1023 1138 end) 1024 1139 1025 1140 -- performs a general HUD refresh, mainly to update the HUD backlight brightness 1026 1141 local hudInterval = 10 1027 1142 starlit.startJob('starlit:hud-refresh', hudInterval, function(delta) 1028 - for id, u in pairs(starlit.activeUsers) do u:updateHUD() end 1143 + for id, u in pairs(starlit.activeUsers) do 1144 + u:updateHUD() end 1029 1145 end) 1030 1146 1031 1147 local biointerval = 1.0 1032 1148 starlit.startJob('starlit:bio', biointerval, function(delta) 1033 1149 for id, u in pairs(starlit.activeUsers) do 1034 1150 if u:effectiveStat 'health' ~= 0 then 1035 1151 local bmr = u:phenoTrait 'metabolism' * biointerval ................................................................................ 1092 1208 1093 1209 if sp < 1.0 and minetest.get_gametime() - u.cooldownTimes.stamina > 5.0 then 1094 1210 u:statDelta('stamina', (u:phenoTrait('staminaRegen',1) * penaltyFromFatigue) / heatPenalty) 1095 1211 -- print('stam', u:effectiveStat 'stamina', u:phenoTrait('staminaRegen',1) / heatPenalty, heatPenalty) 1096 1212 end 1097 1213 1098 1214 local morale, mp = u:effectiveStat 'morale' 1099 - local pr = u:phenoTrait 'psiRegen' 1100 - u:statDelta('psi', pr * penaltyFromFatigue * mp) 1215 + local pr = u:phenoTrait 'numinaRegen' 1216 + u:statDelta('numina', pr * penaltyFromFatigue * mp) 1101 1217 end 1102 1218 end 1103 1219 end) 1104 1220 1105 1221 local cbit = { 1106 1222 up = 0x001; 1107 1223 down = 0x002;
Modified mods/starlit/world.lua from [5368f81f41] to [822a964373].
181 181 for name,user in pairs(starlit.activeUsers) do 182 182 local tr = user:species().tempRange 183 183 local t = starlit.world.climate.temp(user.entity:get_pos()) 184 184 185 185 do -- this bit probably belongs in starlit:bio but we do it here in order 186 186 -- to spare ourselves another call into the dark swamp of climate.temp 187 187 local urg = 1 188 - local function alarm(kind) 189 - user:alarm(urg, kind, nil, { 190 - elt = user.hud.elt.temp, ofs = {x=100,y=0}; 191 - tex = 'starlit-ui-alert-'..kind..'.png'; 192 - }) 193 - end 194 188 local hz = user:tempHazard(t) 195 189 local tr = user:species().tempRange.survivable 196 190 if hz == 'cold' then 197 191 if tr[1] - t > 7 then urg = 2 end 198 - alarm 'temp-cold' 192 + user:alarm(urg, 'freeze', 3) 199 193 elseif hz == 'hot' then 200 194 if t - tr[2] > 7 then urg = 2 end 201 - alarm 'temp-hot' 195 + user:alarm(urg, 'overheat', 3) 202 196 end 203 197 end 204 198 205 199 local insul = 0 206 200 local naked = user:naked() 207 201 local suitDef 208 202 if not naked then
Modified mods/vtlib/math.lua from [43eaf4251e] to [2d47a7e2f1].
156 156 -- function fn.vlerp 157 157 158 158 function fn.timespec(n) 159 159 if n == 0 then return '0s' end 160 160 if n < 0 then return '-' .. fn.timespec(n*-1) end 161 161 162 162 local sec = math.floor(n % 60) 163 - local hr = math.floor(n / 60) 163 + local min = math.floor(n / 60) 164 + local hr = math.floor(min / 60) 164 165 local spec = {} 165 166 166 167 if hr ~= 0 then table.insert(spec, string.format("%shr", hr)) end 168 + if min ~= 0 then table.insert(spec, string.format("%sm", min)) end 167 169 if sec ~= 0 then table.insert(spec, string.format("%ss", sec)) end 168 170 return table.concat(spec, ' ') 169 171 end 170 172 return fn
Modified mods/vtlib/str.lua from [01c1839f00] to [ded7121fc6].
161 161 else 162 162 tbl[#tbl+1] = string.sub(ss,1,d-1) 163 163 end 164 164 until i > string.len(str) 165 165 return tbl 166 166 end; 167 167 168 - rand = function(min,max) 168 + rand = function(rng, min,max) 169 169 if not min then min = 16 end 170 170 if not max then max = min end 171 171 local str = '' 172 172 local r_int = 0x39 - 0x30 173 173 local r_upper = r_int + (0x5a - 0x41) 174 174 local r_lower = r_upper + (0x7a - 0x61) 175 - for i = 1,math.random(max - min) + min do 175 + for i = 1,rng:int(min,max) do 176 176 -- 0x30 -- 0x39 177 177 -- 0x41 -- 0x5A 178 178 -- 0x61 -- 0x71 179 - local codepoint = math.random(r_lower) 179 + local codepoint = rng:int(r_lower) 180 180 if codepoint > r_upper then 181 181 codepoint = (codepoint - r_upper) + 0x61 182 182 elseif codepoint > r_int then 183 183 codepoint = (codepoint - r_int) + 0x41 184 184 else 185 185 codepoint = codepoint + 0x30 186 186 end 187 187 str = str .. string.char(codepoint) 188 188 end 189 189 return str 190 190 end; 191 + 192 + htsan = function(str) 193 + return str:gsub('([<\\])', '\\%1') 194 + end; 191 195 192 196 chop = function(str) 193 197 if string.sub(str, 1,1) == ' ' then 194 198 str = string.sub(str, 2) 195 199 end 196 200 if string.sub(str, #str,#str) == ' ' then 197 201 str = string.sub(str, 1, #str - 1)
Modified starlit.ct from [8d6b5074b6] to [7cb4085b3b].
37 37 38 38 p11143: https://github.com/minetest/minetest/pull/11143.diff 39 39 40 40 ### shadows 41 41 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. 42 42 43 43 ## gameplay 44 -starlit is somewhat unusual in how it uses the minetest engine. it's a voxel game but not of the minecraft variety. 44 +starlit is somewhat unusual in how it uses the minetest engine. it's a voxel game but not of the minecraft variety. you do have some control over your environment, but it's limited and exerting it is much more expensive than you might be used to -- the focus of the game is figuring out how to work with nature, not against it. Farthest Shadow has little patience for those who do not show her the respect a living world is due, and she is unconcerned with human virtues like "mercy" or "fairness" or "proportionate retribution". 45 45 46 -the most important thing to understand about starlit is that is is [*mean], by design. 46 +this is to say, starlit is [*mean], by design. 47 47 48 48 * 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. Farthest Shadow doesn't care about your feelings. 49 49 * 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. 50 50 51 51 ### scenarios 52 -your starting character configuration depends on the scenario you select. (right now this is configured in minetest settings, which is intensely awkward, but i don't have a better solution). the scenario controls your species, sex, and starting inventory. [*neither species nor sex is cosmetic]; e.g. human females are physically weaker but psionically stronged than males. the current playable scenarios are: 52 +your starting character configuration depends on the scenario you select. (right now this is configured in minetest settings, which is intensely awkward, but i don't have a better solution). the scenario controls your species, sex, and starting inventory. [*neither species nor sex is cosmetic]; e.g. human females are physically weaker but psionically stronger than males. the current playable scenarios are: 53 53 54 54 #### Imperial Expat 55 55 [*phenotype]: human female 56 56 [*starting gear]: Commune survival kit 57 57 > Hoping to escape a miserable life deep in the grinding gears of the capitalist machine for the bracing freedom of the frontier, you sought entry as a colonist to the new Commune world of Thousand Petal. Fate -- which is to say, terrorists -- intervened, and you wound up stranded on Farthest Shadow with little more than the nanosuit on your back, ship blown to tatters and your soul thoroughly mauled by the explosion of a twisted alien artifact -- which SOMEONE neglected to inform you your ride would be carrying. 58 58 > At least you got some handy psionic powers out of this whole clusterfuck. Hopefully they're safe to use. 59 59 60 60 #### Gentleman Adventurer [!(unimplemented)] 61 61 [*phenotype]: human male 62 62 [*starting gear]: Imperial survival kit 63 -> Tired of the same-old-same-old, sick of your idiot contemporaries, exasperated with the shallow soul-rotting luxury of life as landless lordling, and earnestly eager to enrage your father, you resolved to see the Reach in all her splendor. Deftly evading the usual tourist traps, you finagled your way into the confidence of the Commune ambassador with a few modest infusions of Father's money -- now [!that] should pop his monocle -- and secured yourself a seat on a ride to their brand-new colony at Thousand Petal. How exciting -- a genuine frontier outing! 63 +> Tired of the same-old-same-old, sick of your idiot contemporaries, exasperated with the shallow soul-rotting luxury of life as landless lordling, and earnestly eager to enrage your father, you resolved to see the Reach in all her splendor. Deftly evading the usual tourist traps, you finagled your way into the confidence of the Commune ambassador with a few modest infusions of Father's money -- now [!that] should pop his monocle! -- and secured yourself a seat on a ride to their brand-new colony at Thousand Petal. 64 +> How exciting -- a genuine frontier outing! 64 65 65 66 #### Terrorist Tagalong 66 67 [*phenotype]: human female 67 68 [*starting gear]: star merc combat kit 68 69 > It turns out there's a *reason* Crown jobs pay so well. 69 70 70 71 #### Tradebird Bodyguard [!(unimplemented)]