Overview
Comment: | add to lore, add weather data, etc |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
caec179da98b03b03ac6b8b215692f17 |
User & Date: | lexi on 2025-01-19 19:05:09 |
Other Links: | manifest | tags |
Context
2025-01-19
| ||
19:18 | we have always been at war with east minecraft Leaf check-in: 4732f8d454 user: lexi tags: trunk | |
19:05 | add to lore, add weather data, etc check-in: caec179da9 user: lexi tags: trunk | |
2024-12-19
| ||
20:03 | unfuck cpio invocations check-in: e926621707 user: root tags: trunk | |
Changes
Modified dev.ct from [912982b94d] to [51e6dca729].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# starlit development this file contains information meant for those who wish to develop for Starsoul or build the game from trunk. do NOT add any story information, particularly spoilers; those go in src/lore.ct. ## tooling starlit uses the following software in the development process: * [*csound] to generate sound effects * [*GNU make] to automate build tasks * [*lua] to automate configure tasks ## building to run a trunk version of Starsoul, you'll need to install the above tools and run `make` from the base directory. this will: * run lua scripts to generate necessary makefiles * generate the game sound effects and install them in mods/starlit/sounds ## policy * copyright of all submitted code must be reassigned to the maintainer. * all code is to be indented with tabs and aligned with spaces; formatting is otherwise up to whoever is responsible for maintaining that code * use [`camelCase], not [`snake_case] and CERTAINLY not [`SCREAMING_SNAKE_CASE] * sounds effects should be contributed in the form of csound files; avoid adding audio files to the repository except for foley effects |
| | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# starlit development this file contains information meant for those who wish to develop for Starlit or build the game from trunk. do NOT add any story information, particularly spoilers; those go in src/lore.ct. ## tooling starlit uses the following software in the development process: * [*csound] to generate sound effects * [*GNU make] to automate build tasks * [*lua] to automate configure tasks ## building to run a trunk version of Starlit, you'll need to install the above tools and run `make` from the base directory. this will: * run lua scripts to generate necessary makefiles * generate the game sound effects and install them in mods/starlit/sounds ## policy * copyright of all submitted code must be reassigned to the maintainer. * all code is to be indented with tabs and aligned with spaces; formatting is otherwise up to whoever is responsible for maintaining that code * use [`camelCase], not [`snake_case] and CERTAINLY not [`SCREAMING_SNAKE_CASE] * sounds effects should be contributed in the form of csound files; avoid adding audio files to the repository except for foley effects |
Modified mods/starlit-eco/init.lua from [fb6e06be08] to [f0d21c2132].
11 12 13 14 15 16 17 18 19 20 21 22 23 24 .. 27 28 29 30 31 32 33 34 35 36 37 38 39 40 .. 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 .. 73 74 75 76 77 78 79 80 81 82 83 84 85 86 .. 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 |
node_filler = 'starlit:soil', depth_filler = 4; node_riverbed = 'starlit:sand', depth_riverbed = 4; y_min = 0; y_max = 56; heat_point = 50; humidity_point = 40; }; }) world.ecology.biomes.link('starlit:forest', { nightTempDelta = -20; waterTempDelta = 0; -- W Sp Su Au W seasonalTemp = {-40, -8, 10, 10, -14, -40}; ................................................................................ node_filler = 'starlit:soil', depth_filler = 4; node_riverbed = 'starlit:sand', depth_riverbed = 4; y_min = 0; y_max = 256; heat_point = 60; humidity_point = 45; }; }) world.ecology.biomes.link('starlit:desert', { nightTempDelta = -40; waterTempDelta = 0; -- W Sp Su Au W seasonalTemp = {-10, -5, 15, 15, -5, -10}; ................................................................................ node_filler = 'starlit:sand', depth_filler = 4; node_riverbed = 'starlit:sand', depth_riverbed = 4; y_min = 0; y_max = 512; heat_point = 70; 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 = 60; humidity_point = 70; node_top = 'starlit:sand', depth_top = 1; node_filler = 'starlit:sand', depth_filler = 3; }; }) world.ecology.biomes.link('starlit:shiverdeep', { nightTempDelta = -25; waterTempDelta = 5; -- W Sp Su Au W seasonalTemp = {-70, -30, 0, -60, -70}; ................................................................................ y_min = 0; heat_point = 20; humidity_point = 30; node_water_top = 'starlit:ice', depth_water_top = 1; node_top = 'starlit:undergloam', depth_top = 1; node_filler = 'starlit:soil', depth_filler = 2; }; }) world.ecology.biomes.link('starlit:silthaven', { nightTempDelta = -5; waterTempDelta = 5; -- W Sp Su Au W seasonalTemp = {-15, 5, 15, 7, -15}; ................................................................................ y_max = 30; y_min = 0; heat_point = 30; humidity_point = 30; -- node_top = 'starlit:undergloam', depth_top = 1; node_filler = 'starlit:lifesilt', depth_filler = 5; }; }) world.ecology.biomes.link('starlit:barrens', { nightTempDelta = -20; waterTempDelta = 5; -- W Sp Su Au W seasonalTemp = {-30, -20, 0, -20, -30}; def = { y_max = 512; y_min = -512; heat_point = 0; humidity_point = 0; }; }) 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) |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 .. 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 .. 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 ... 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 ... 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 |
node_filler = 'starlit:soil', depth_filler = 4; node_riverbed = 'starlit:sand', depth_riverbed = 4; y_min = 0; y_max = 56; heat_point = 50; humidity_point = 40; }; weather = { {-0.900, 'starlit:meteorShower'}; {-0.700, 'starlit:sstorm'}; {-0.100, 'starlit:clear'}; {0.300, 'starlit:cloudy'}; {0.400, 'starlit:precip'}; {0.450, 'starlit:storm'}; {0.500, 'starlit:tstorm'}; }; }) world.ecology.biomes.link('starlit:forest', { nightTempDelta = -20; waterTempDelta = 0; -- W Sp Su Au W seasonalTemp = {-40, -8, 10, 10, -14, -40}; ................................................................................ node_filler = 'starlit:soil', depth_filler = 4; node_riverbed = 'starlit:sand', depth_riverbed = 4; y_min = 0; y_max = 256; heat_point = 60; humidity_point = 45; }; weather = { {-0.900, 'starlit:meteorShower'}; {-0.700, 'starlit:sstorm'}; {-0.100, 'starlit:clear'}; {0.200, 'starlit:cloudy'}; {0.400, 'starlit:precip'}; {0.650, 'starlit:storm'}; {0.800, 'starlit:tstorm'}; }; }) world.ecology.biomes.link('starlit:desert', { nightTempDelta = -40; waterTempDelta = 0; -- W Sp Su Au W seasonalTemp = {-10, -5, 15, 15, -5, -10}; ................................................................................ node_filler = 'starlit:sand', depth_filler = 4; node_riverbed = 'starlit:sand', depth_riverbed = 4; y_min = 0; y_max = 512; heat_point = 70; humidity_point = 10; }; weather = { {-0.900, 'starlit:meteorShower'}; {-0.700, 'starlit:sstorm'}; {-0.100, 'starlit:clear'}; {0.400, 'starlit:cloudy'}; {0.850, 'starlit:tstorm'}; }; }) world.ecology.biomes.link('starlit:ocean', { nightTempDelta = -35; waterTempDelta = 5; seasonalTemp = {0}; -- no seasonal variance def = { ................................................................................ y_max = 3; y_min = -512; heat_point = 60; humidity_point = 70; node_top = 'starlit:sand', depth_top = 1; node_filler = 'starlit:sand', depth_filler = 3; }; weather = { {-0.900, 'starlit:meteorShower'}; {-0.700, 'starlit:sstorm'}; {-0.100, 'starlit:clear'}; {0.300, 'starlit:cloudy'}; {0.500, 'starlit:precip'}; {0.650, 'starlit:storm'}; {0.800, 'starlit:tstorm'}; }; }) world.ecology.biomes.link('starlit:shiverdeep', { nightTempDelta = -25; waterTempDelta = 5; -- W Sp Su Au W seasonalTemp = {-70, -30, 0, -60, -70}; ................................................................................ y_min = 0; heat_point = 20; humidity_point = 30; node_water_top = 'starlit:ice', depth_water_top = 1; node_top = 'starlit:undergloam', depth_top = 1; node_filler = 'starlit:soil', depth_filler = 2; }; weather = { {-0.900, 'starlit:meteorShower'}; {-0.700, 'starlit:sstorm'}; {-0.100, 'starlit:clear'}; {0.200, 'starlit:cloudy'}; {0.400, 'starlit:precip'}; {0.650, 'starlit:storm'}; {0.900, 'starlit:tstorm'}; }; }) world.ecology.biomes.link('starlit:silthaven', { nightTempDelta = -5; waterTempDelta = 5; -- W Sp Su Au W seasonalTemp = {-15, 5, 15, 7, -15}; ................................................................................ y_max = 30; y_min = 0; heat_point = 30; humidity_point = 30; -- node_top = 'starlit:undergloam', depth_top = 1; node_filler = 'starlit:lifesilt', depth_filler = 5; }; weather = { {-0.900, 'starlit:meteorShower'}; {-0.700, 'starlit:sstorm'}; {-0.100, 'starlit:clear'}; {0.400, 'starlit:cloudy'}; {0.600, 'starlit:precip'}; {0.750, 'starlit:storm'}; {0.900, 'starlit:tstorm'}; }; }) world.ecology.biomes.link('starlit:barrens', { nightTempDelta = -20; waterTempDelta = 5; -- W Sp Su Au W seasonalTemp = {-30, -20, 0, -20, -30}; def = { y_max = 512; y_min = -512; heat_point = 0; humidity_point = 0; }; weather = { {-0.900, 'starlit:meteorShower'}; {-0.600, 'starlit:sstorm'}; {-0.100, 'starlit:clear'}; { 0.300, 'starlit:cloudy'}; { 0.600, 'starlit:precip'}; { 0.850, 'starlit:storm'}; { 0.900, 'starlit:tstorm'}; }; }) 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) |
Modified mods/starlit-tech/init.lua from [22b6956759] to [91056054d4].
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
|
} end; } minetest.register_node('starlit_tech:crate', { short_description = 'Crate'; description = starlit.ui.tooltip { title = 'Crate'; desc = 'A sturdy but lightweight storage crate woven from graphene.'; props = { {title='Mass', affinity='info', desc='100g'} }; }; drawtype = 'nodebox'; node_box = { type = 'fixed'; fixed = { .4, .2, .4; ................................................................................ _starlit = { mass = 100; reverseEngineer = { complexity = 1; sw = 'starlit_tech:schematic_crate'; }; recover = starlit.type.fab { element = { carbon = 100; }; time = { shred = 1; shredPower = 3; }; }; }; on_construct = function(pos) |
|
|
|
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
|
} end; } minetest.register_node('starlit_tech:crate', { short_description = 'Crate'; description = starlit.ui.tooltip { title = 'Crate'; desc = 'A sturdy but lightweight aluminum storage crate.'; props = { {title='Mass', affinity='info', desc='100g'} }; }; drawtype = 'nodebox'; node_box = { type = 'fixed'; fixed = { .4, .2, .4; ................................................................................ _starlit = { mass = 100; reverseEngineer = { complexity = 1; sw = 'starlit_tech:schematic_crate'; }; recover = starlit.type.fab { element = { aluminum = 100; }; time = { shred = 1; shredPower = 3; }; }; }; on_construct = function(pos) |
Modified mods/starlit/init.lua from [44e70e86d4] to [277b90dbc5].
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
...
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
liquid = lib.registry.mk 'starlit:liquid'; }; ecology = { plants = lib.registry.mk 'starlit:plants'; trees = lib.registry.mk 'starlit:trees'; biomes = lib.registry.mk 'starlit:biome'; }; climate = {}; scenario = {}; planet = { gravity = 7.44; orbit = 189; -- 1 year is 189 days revolve = 20; -- 1 day is 20 irl minutes }; fact = lib.registry.mk 'starlit:fact'; ................................................................................ }; }; }; }; jobs = {}; } starlit.cfgDir = minetest.get_worldpath() .. '/' .. starlit.ident local logger = function(module) local function argjoin(arg, nxt, ...) if arg and not nxt then return tostring(arg) end if not arg then return "(nil)" end |
|
>
>
>
>
>
|
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
...
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
liquid = lib.registry.mk 'starlit:liquid'; }; ecology = { plants = lib.registry.mk 'starlit:plants'; trees = lib.registry.mk 'starlit:trees'; biomes = lib.registry.mk 'starlit:biome'; }; climate = { weather = lib.registry.mk 'starlit:weather'; weatherMap = {} }; scenario = {}; planet = { gravity = 7.44; orbit = 189; -- 1 year is 189 days revolve = 20; -- 1 day is 20 irl minutes }; fact = lib.registry.mk 'starlit:fact'; ................................................................................ }; }; }; }; jobs = {}; } -- TODO deal with core.DEFAULT_PHYSICS once it hits master starlit.cfgDir = minetest.get_worldpath() .. '/' .. starlit.ident local logger = function(module) local function argjoin(arg, nxt, ...) if arg and not nxt then return tostring(arg) end if not arg then return "(nil)" end |
Modified mods/starlit/user.lua from [ae84fc4236] to [9accce5f34].
103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
calendar = 'commune'; }; overlays = {}; cooldownTimes = { stamina = 0; alarm = 0; }; } end; __index = { -------------- -- overlays -- -------------- updateOverlays = function(self) |
> > > |
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
calendar = 'commune'; }; overlays = {}; cooldownTimes = { stamina = 0; alarm = 0; }; env = { weather = nil; }; } end; __index = { -------------- -- overlays -- -------------- updateOverlays = function(self) |
Modified mods/starlit/world.lua from [d1f4916ac1] to [de51a702a5].
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 .. 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 ... 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 |
surfaceTemp = heat; waterTemp = heat + biome.waterTempDelta; surfaceHumid = humid; } end local vdsq = lib.math.vdsq function world.climate.temp(pos) --> irradiance at pos in W local cl = world.climate.eval(pos) local radCenters = starlit.region.radiator.store:get_areas_for_pos(pos, false, true) local irradiance = 0 for _,e in pairs(radCenters) do local rpos = minetest.string_to_pos(e.data) local rdef = assert(minetest.registered_nodes[assert(minetest.get_node(rpos)).name]) local rc = rdef._starlit.radiator ................................................................................ power = power * (1 - (dist_sq / ((r_max+1)^2))) end power = power * (1 - (obstruct/5)) irradiance = irradiance + power end end end return irradiance + cl.surfaceTemp end world.ecology.biomes.foreach('starlit:biome-gen', {}, function(id, b) b.def.name = id minetest.register_biome(b.def) end) world.ecology.plants.foreach('starlit:plant-gen', {}, function(id, b) ................................................................................ } for k,v in pairs(b.decoration) do dec[k] = v end b.decoration = minetest.register_decoration(dec) end) local toward = lib.math.toward local hfinterval = 1.5 starlit.startJob('starlit:heatflow', hfinterval, function(delta) -- our base thermal conductivity (κ) is measured in °C/°C/s. say the -- player is in -30°C weather, and has an internal temperature of -- 10°C. then: -- κ = .1°C/C/s (which is apparently 100mHz) -- Tₚ = 10°C -- Tₑ = -30°C ................................................................................ -- d = Tₑ − Tₚ = -40°C -- ΔT = κ×d = -.4°C/s -- too cold: -- x = beginning of danger zone -- κ × (x - Tₚ) = y where y < Tₚ -- our final change in temperature is computed as tΔC where t is time local kappa = starlit.constant.heat.thermalConductivity for name,user in pairs(starlit.activeUsers) do local tr = user:species().tempRange local t = starlit.world.climate.temp(user.entity:get_pos()) do -- this bit probably belongs in starlit:bio but we do it here in order -- to spare ourselves another call into the dark swamp of climate.temp local urg = 1 local hz = user:tempHazard(t) local tr = user:species().tempRange.survivable if hz == 'cold' then |
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > |
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 .. 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 ... 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 ... 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
surfaceTemp = heat; waterTemp = heat + biome.waterTempDelta; surfaceHumid = humid; } end local vdsq = lib.math.vdsq function world.climate.temp(pos, timeshift) --> irradiance at pos in W local cl = world.climate.eval(pos) local radCenters = starlit.region.radiator.store:get_areas_for_pos(pos, false, true) local irradiance = 0 for _,e in pairs(radCenters) do local rpos = minetest.string_to_pos(e.data) local rdef = assert(minetest.registered_nodes[assert(minetest.get_node(rpos)).name]) local rc = rdef._starlit.radiator ................................................................................ power = power * (1 - (dist_sq / ((r_max+1)^2))) end power = power * (1 - (obstruct/5)) irradiance = irradiance + power end end end local w = world.climate.weatherAt(pos, timeshift) return irradiance + cl.surfaceTemp end function world.ecology.biomeAt(pos) return world.ecology.biomes.db[minetest.get_biome_name(minetest.get_biome_data(pos).biome)] end minetest.after(0, function() world.climate.weatherMap.kind = minetest.get_perlin { seed = 0x925afe; octaves = 2; spread = vector.new(256,256,120); }; world.climate.weatherMap.severity = minetest.get_perlin { seed = 0x39de1d; octaves = 1; spread = vector.new(256,256,60); }; end) function world.climate.weatherAt(pos, timeshift) timeshift = timeshift or 0 local wv = world.climate.weatherMap.kind:get_3d(vector.new(pos.x, pos.z, minetest.get_gametime() + timeshift)) local sev = world.climate.weatherMap.severity:get_3d(vector.new(pos.x, pos.z, minetest.get_gametime() + timeshift)) local b = world.ecology.biomeAt(pos) local w = 'starlit:clear' for i,v in ipairs(b.weather) do if wv < v[1] then w = v[2] break end end local mods = { cloudCover = 0; rain = 0; -- affects plant growth snow = 0; -- spawns snow layer fog = 0; temp = 0; hum = 0; rad = 0; } return world.climate.weather.db[w], sev end -- weather manages particle systems, and provides modifiers for -- temp, cloud cover, received precipitation, and fog world.climate.weather.link('starlit:clear', { name = 'Clear'; }) world.climate.weather.link('starlit:cloudy', { name = 'Cloudy'; mod = function(m, temp, hum, sev) m.cloudCover = math.max(m.cloudCover, sev) end; }) world.climate.weather.link('starlit:precip', { name = function(temp, hum, sev) if temp < 0 then return 'Snow' else return 'Rain' end end; mod = function(m, temp, hum, sev) m.cloudCover = math.max(m.cloudCover, sev) if temp < 0 then m.snow = math.max(m.snow, sev/2) else m.rain = math.max(m.rain, sev/2) end end; }) world.climate.weather.link('starlit:storm', { name = function(temp, hum, sev) if temp < 0 then if sev > .5 then return 'Blizzard' else return 'Snowstorm' end else if sev > .5 then return 'Monsoon' else return 'Rainstorm' end end end; mod = function(m, temp, hum, sev) m.cloudCover = math.max(m.cloudCover, sev) if temp < 0 then m.snow = math.max(m.snow, sev/2 + .5) else m.rain = math.max(m.rain, sev/2 + .5) end end; }) world.climate.weather.link('starlit:tstorm', { name = 'Thunderstorm'; danger = 1; mod = function(m, temp, hum, sev) m.cloudCover = math.max(m.cloudCover, sev) m.danger = (sev>.5) and 2 or 1 end; }) world.climate.weather.link('starlit:sstorm', { name = 'Solar Storm'; danger = 2; }) world.climate.weather.link('starlit:meteorShower', { name = 'Meteor Shower'; danger = 2; }) world.ecology.biomes.foreach('starlit:biome-gen', {}, function(id, b) b.def.name = id minetest.register_biome(b.def) end) world.ecology.plants.foreach('starlit:plant-gen', {}, function(id, b) ................................................................................ } for k,v in pairs(b.decoration) do dec[k] = v end b.decoration = minetest.register_decoration(dec) end) local toward = lib.math.toward local hfinterval = 1.5 starlit.startJob('starlit:temps', hfinterval, function(delta) -- our base thermal conductivity (κ) is measured in °C/°C/s. say the -- player is in -30°C weather, and has an internal temperature of -- 10°C. then: -- κ = .1°C/C/s (which is apparently 100mHz) -- Tₚ = 10°C -- Tₑ = -30°C ................................................................................ -- d = Tₑ − Tₚ = -40°C -- ΔT = κ×d = -.4°C/s -- too cold: -- x = beginning of danger zone -- κ × (x - Tₚ) = y where y < Tₚ -- our final change in temperature is computed as tΔC where t is time local kappa = starlit.constant.heat.thermalConductivity local now = minetest.get_gametime() for name,user in pairs(starlit.activeUsers) do local tr = user:species().tempRange local t = starlit.world.climate.temp(user.entity:get_pos()) local weather,wsev = starlit.world.climate.weatherAt(user.entity:get_pos()) local wfac if user.env.weather == nil then wfac = 1 else wfac = (now - user.env.weather.when) / 10 end if user.env.weather == nil or now - user.env.weather.when >= 10 then user.env.weather = {when = now, what = weather} end do -- this bit probably belongs in starlit:bio but we do it here in order -- to spare ourselves another call into the dark swamp of climate.temp local urg = 1 local hz = user:tempHazard(t) local tr = user:species().tempRange.survivable if hz == 'cold' then |
Modified mods/vtlib/init.lua from [d31a921c62] to [d021d078eb].
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
if chunk == nil then error(err) end lib[name] = chunk(lib, ident, path) end component 'dbg' -- primitive manip component 'tbl' component 'class' component 'math' component 'str' -- reading and writing data formats component 'marshal' -- classes component 'color' |
| | | |
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
if chunk == nil then error(err) end lib[name] = chunk(lib, ident, path) end component 'dbg' -- primitive manip component 'class' component 'math' component 'tbl' component 'str' -- reading and writing data formats component 'marshal' -- classes component 'color' |
Modified mods/vtlib/math.lua from [3e36361725] to [65dcc21fc6].
20
21
22
23
24
25
26
27
28
29
30
31
32
33
..
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
end local dsq = (d.x ^ 2) + (d.y ^ 2) + (d.z ^ 2) return dsq / (dist^2) -- [0,1) == less then -- 1 == equal -- >1 == greater than end -- produce an SI expression for a quantity fn.si = function(unit, val, full, uncommonScales, prec) if val == 0 then return '0 ' .. unit end local scales = { {30, 'Q', 'quetta',true, 'q', 'quecto',true}; {27, 'R', 'ronna', true, 'r', 'ronto', true}; ................................................................................ end end return unit end for i, s in ipairs(scales) do local amt, smaj, pmaj, cmaj, smin, pmin, cmin = lib.tbl.unpack(s) if math.abs(val) > 1 then if uncommonScales or cmaj then local denom = 10^amt local vd = val/denom if prec then vd = lib.math.trim(vd, prec) end |
>
>
|
|
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
..
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
end local dsq = (d.x ^ 2) + (d.y ^ 2) + (d.z ^ 2) return dsq / (dist^2) -- [0,1) == less then -- 1 == equal -- >1 == greater than end local unpack = table.unpack or unpack -- produce an SI expression for a quantity fn.si = function(unit, val, full, uncommonScales, prec) if val == 0 then return '0 ' .. unit end local scales = { {30, 'Q', 'quetta',true, 'q', 'quecto',true}; {27, 'R', 'ronna', true, 'r', 'ronto', true}; ................................................................................ end end return unit end for i, s in ipairs(scales) do local amt, smaj, pmaj, cmaj, smin, pmin, cmin = unpack(s) if math.abs(val) > 1 then if uncommonScales or cmaj then local denom = 10^amt local vd = val/denom if prec then vd = lib.math.trim(vd, prec) end |
Modified mods/vtlib/tbl.lua from [ed1f208dfe] to [ae7901fd4c].
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
...
251
252
253
254
255
256
257
258
259
|
fn.pick = function(lst)
local keys = fn.keys(lst)
local k = keys[math.random(#keys)]
return k, lst[k]
end
fn.unpack = table.unpack or unpack or function(tbl,i)
i = i or 1
if #tbl == i then return tbl[i] end
return tbl[i], fn.unpack(tbl, i+1)
end
fn.split = function(...) return fn.unpack(lib.str.explode(...)) end
fn.each = function(tbl,f)
local r = {}
for k,v in pairs(tbl) do
local v, c = f(v,k)
................................................................................
fn.set = function(...)
local s = {}
fn.setOrD(s, ...)
return s
end
return fn
|
|
|
>
>
>
>
>
>
>
|
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
...
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
|
fn.pick = function(lst) local keys = fn.keys(lst) local k = keys[math.random(#keys)] return k, lst[k] end fn.unpack = table.unpack or unpack --[[or function(tbl,i) i = i or 1 if #tbl == i then return tbl[i] end return tbl[i], fn.unpack(tbl, i+1) end]] fn.split = function(...) return fn.unpack(lib.str.explode(...)) end fn.each = function(tbl,f) local r = {} for k,v in pairs(tbl) do local v, c = f(v,k) ................................................................................ fn.set = function(...) local s = {} fn.setOrD(s, ...) return s end fn.lerp = function(t, a, b) local r = {} for k in next, a do r[k] = lib.math.lerp(t, a[k], b[k]) end return r end return fn |
Modified src/lore.ct from [176ec871ae] to [dab20c55bd].
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
within the Web itself, they mostly by clandestine means, using "Agents" selected from the Greater (and, occasionally, Lesser) Races to act on their behalf. in general they act directly only when overwhelming force is required, such as to exclude the Kuradoqshe, or to excise Suldibrand.
it is known that the Eluthrai are of great intelligence: a 200pt IQ makes you a laughable simpleton in their eyes. it is estimated that the average individual has an IQ of 290, close to the theoretical maximum where organized intelligence dissolves into a sea of blinding psychosis. consequently, they are very conservative and cautious of new ideas; their culture emphasises skepticism and avoiding rash action.
early Eluthran history was extremely warlike, and they could have easily devastated the whole of the Reach in their fanatical pursuit of competing ideologies. however, a philosophical tradition emerged from the rubble of a particularly ruinous exchange that offered the correct tools for neutering the more dangerous aspects of their intelligence -- after the centuries proved its value, the Philosophers exterminated all the remaining Eluthrai who had not adopted their practices. it was a coldblooded but rational act of genocide: an individual Eluthra is intelligent enough to bootstrap an industrial civilization from first principles with a few years of effort. an entire civilization of them, devoid of self-control? that wasn't merely a threat to the Philosophers; it was a threat to the Galaxy entire.
the Eluthrai have a single common language, Eluthric, which they use in interstellar discourse and in the sciences. however, the different far-flung colonies have their own individual tongues as well. Eluthric has the largest vocabulary of any known language, with over twenty million words. an Eluthra who hasn't learned at least a million of them by adolescence is deemed slow.
they have developed very slowly since the Philosophers came to power, but were already so advanced that nobody is expected to exceed them any time soon.
Eluthran civilization is united under the rule of the Philosopher-King, an enlightened despot with unrestricted power, in a complex web of fealty and patronage collectively named the Corcordance of the Eluthrai. while the First Philosopher died tens of thousands of years ago, he had the foresight to prepare a successor to take his place in case of his assassination or ill-fortune. in all those years, power has changed hands only three times. the current Philosopher-King has ruled for eight thousand years.
Eluthrai have two genders, and dramatic dimorphism. their women are much more intelligent than their men, and proportionately more prone to psychosis. traditionally most of their societies were matriarchal -- with the brains and psionic brawn to overpower the males, there was very little that could keep the Clan-Queens from exerting their will. the First Philosopher recognized however that the lesser intelligence of men was useful, due to their stabler psyches, and proposed patriarchy as part of his solution. this was made possible through a previously obscure psionic technique known as quelling -- with enough intimate exposure to the soul of another, it becomes possible to negate their psionics, even if that psion is stronger.
|
| |
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
within the Web itself, they mostly by clandestine means, using "Agents" selected from the Greater (and, occasionally, Lesser) Races to act on their behalf. in general they act directly only when overwhelming force is required, such as to exclude the Kuradoqshe, or to excise Suldibrand.
it is known that the Eluthrai are of great intelligence: a 200pt IQ makes you a laughable simpleton in their eyes. it is estimated that the average individual has an IQ of 290, close to the theoretical maximum where organized intelligence dissolves into a sea of blinding psychosis. consequently, they are very conservative and cautious of new ideas; their culture emphasises skepticism and avoiding rash action.
early Eluthran history was extremely warlike, and they could have easily devastated the whole of the Reach in their fanatical pursuit of competing ideologies. however, a philosophical tradition emerged from the rubble of a particularly ruinous exchange that offered the correct tools for neutering the more dangerous aspects of their intelligence -- after the centuries proved its value, the Philosophers exterminated all the remaining Eluthrai who had not adopted their practices. it was a coldblooded but rational act of genocide: an individual Eluthra is intelligent enough to bootstrap an industrial civilization from first principles with a few years of effort. an entire civilization of them, devoid of self-control? that wasn't merely a threat to the Philosophers; it was a threat to the Galaxy entire.
the Eluthrai have a single common language, Iluthanna ("Eluthric" as the Crystal Sea calls it), which they use in interstellar discourse and in the sciences. however, the different far-flung colonies have their own individual tongues as well. Eluthric has the largest vocabulary of any known language, with over twenty million words. an Eluthra who hasn't learned at least a million of them by adolescence is deemed slow.
they have developed very slowly since the Philosophers came to power, but were already so advanced that nobody is expected to exceed them any time soon.
Eluthran civilization is united under the rule of the Philosopher-King, an enlightened despot with unrestricted power, in a complex web of fealty and patronage collectively named the Corcordance of the Eluthrai. while the First Philosopher died tens of thousands of years ago, he had the foresight to prepare a successor to take his place in case of his assassination or ill-fortune. in all those years, power has changed hands only three times. the current Philosopher-King has ruled for eight thousand years.
Eluthrai have two genders, and dramatic dimorphism. their women are much more intelligent than their men, and proportionately more prone to psychosis. traditionally most of their societies were matriarchal -- with the brains and psionic brawn to overpower the males, there was very little that could keep the Clan-Queens from exerting their will. the First Philosopher recognized however that the lesser intelligence of men was useful, due to their stabler psyches, and proposed patriarchy as part of his solution. this was made possible through a previously obscure psionic technique known as quelling -- with enough intimate exposure to the soul of another, it becomes possible to negate their psionics, even if that psion is stronger.
|