starlit  Check-in [cade6683f7]

Overview
Comment:add sprint, improve bio job, rebalance stamina regen, various fixes
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: cade6683f70db136391f34c5e60f9f814155147ceabd8900b026116fa94b97e4
User & Date: lexi on 2024-05-03 00:10:09
Other Links: manifest | tags
Context
2024-05-03
13:40
ui latency/performance improvements, bugfixes check-in: f1e68eb97e user: lexi tags: trunk
00:10
add sprint, improve bio job, rebalance stamina regen, various fixes check-in: cade6683f7 user: lexi tags: trunk
2024-05-02
20:27
check in missing mod, add forest biome, racial powers, overlays (untested) check-in: 6deb9bedbc user: lexi tags: trunk
Changes

Modified mods/starlit-eco/init.lua from [ffe9d8ff5f] to [0a9075eccb].

     8      8   	seasonalTemp = {-50, -10, 5, 5, -20, -50};
     9      9   	def = {
    10     10   		node_top      = 'starlit:greengraze', depth_top = 1;
    11     11   		node_filler   = 'starlit:soil',    depth_filler = 4;
    12     12   		node_riverbed = 'starlit:sand',  depth_riverbed = 4;
    13     13   		y_min = 0;
    14     14   		y_max = 512;
    15         -		heat_point = 10;
    16         -		humidity_point = 30;
           15  +		heat_point = 20;
           16  +		humidity_point = 35;
    17     17   	};
    18     18   })
    19     19   
    20     20   world.ecology.biomes.link('starlit:forest', {
    21     21   	nightTempDelta = -20;
    22     22   	waterTempDelta = 0;
    23     23   	--               W    Sp   Su    Au   W
    24     24   	seasonalTemp = {-40, -8, 10, 10, -14, -40};
    25     25   	def = {
    26     26   		node_top      = 'starlit:greengraze', depth_top = 1;
    27     27   		node_filler   = 'starlit:soil',    depth_filler = 4;
    28     28   		node_riverbed = 'starlit:sand',  depth_riverbed = 4;
    29         -		y_min = -100;
           29  +		y_min = 0;
    30     30   		y_max = 256;
    31         -		heat_point = 13;
           31  +		heat_point = 50;
    32     32   		humidity_point = 40;
    33     33   	};
    34     34   })
    35     35   
    36     36   world.ecology.biomes.link('starlit:desert', {
    37     37   	nightTempDelta = -40;
    38     38   	waterTempDelta = 0;
................................................................................
    40     40   	seasonalTemp = {-10, -5, 15, 15, -5, -10};
    41     41   	def = {
    42     42   		node_top      = 'starlit:sand',  depth_top = 1;
    43     43   		node_filler   = 'starlit:sand',  depth_filler = 4;
    44     44   		node_riverbed = 'starlit:sand',  depth_riverbed = 4;
    45     45   		y_min = 0;
    46     46   		y_max = 512;
    47         -		heat_point = 20;
           47  +		heat_point = 70;
    48     48   		humidity_point = 10;
    49     49   	};
    50     50   })
    51     51   
    52     52   world.ecology.biomes.link('starlit:ocean', {
    53     53   	nightTempDelta = -35;
    54     54   	waterTempDelta = 5;
    55     55   	seasonalTemp = {0}; -- no seasonal variance
    56     56   	def = {
    57     57   		y_max = 3;
    58     58   		y_min = -512;
    59         -		heat_point = 15;
    60         -		humidity_point = 50;
           59  +		heat_point = 50;
           60  +		humidity_point = 70;
    61     61   		node_top    = 'starlit:sand', depth_top    = 1;
    62     62   		node_filler = 'starlit:sand', depth_filler = 3;
    63     63   	};
    64     64   })
    65     65   
           66  +world.ecology.biomes.link('starlit:shiverdeep', {
           67  +	nightTempDelta = -25;
           68  +	waterTempDelta = 5;
           69  +	--               W    Sp  Su   Au   W
           70  +	seasonalTemp = {-70, -30, 0,  -60, -70};
           71  +	def = {
           72  +		y_max = 70;
           73  +		y_min = 1;
           74  +		heat_point = 0;
           75  +		humidity_point = 5;
           76  +		node_water_top = 'starlit:ice', depth_water_top = 1;
           77  +		node_top    = 'starlit:undergloam', depth_top    = 1;
           78  +		node_filler = 'starlit:soil',       depth_filler = 2;
           79  +	};
           80  +})
           81  +
           82  +world.ecology.biomes.link('starlit:silthaven', {
           83  +	nightTempDelta = -5;
           84  +	waterTempDelta = 5;
           85  +	--               W  Sp  Su   Au   W
           86  +	seasonalTemp = {-15, 5, 15,  7, -15};
           87  +	def = {
           88  +		y_max = 30;
           89  +		y_min = 0;
           90  +		heat_point = 15;
           91  +		humidity_point = 35;
           92  +-- 		node_top    = 'starlit:undergloam', depth_top    = 1;
           93  +		node_filler = 'starlit:lifesilt',       depth_filler = 5;
           94  +	};
           95  +})
           96  +
           97  +world.ecology.biomes.link('starlit:barrens', {
           98  +	nightTempDelta = -20;
           99  +	waterTempDelta = 5;
          100  +	--                 W  Sp  Su   Au   W
          101  +	seasonalTemp = {-30, -20, 0,  -20, -30};
          102  +	def = {
          103  +		y_max = 512;
          104  +		y_min = 0;
          105  +		heat_point = 0;
          106  +		humidity_point = 0;
          107  +	};
          108  +})
    66    109   minetest.register_craftitem('starlit_eco:fiber', {
    67    110   	description = "Plant Fiber";
    68    111   	groups = {fiber = 1};
    69    112   	inventory_image = lib.image('starlit-eco-plant-fiber.png'):shift(lib.color(0,1,0)):render();
    70    113   	_starlit = {
    71    114   		recover_vary = function(rng, ctx)
    72    115   			return starlit.type.fab {

Modified mods/starlit-eco/plants.lua from [e9756bfa75] to [f0b6b474f2].

   120    120   	color = lib.color(.5, .7, 1);
   121    121   	biolum = 5;
   122    122   	leaf = {
   123    123   		color = lib.color(.6, .8, .8);
   124    124   		drop = simpleDrop(2, 'starlit_eco:moondrop_petal');
   125    125   	};
   126    126   	berries = {
   127         -		desc = "The fruits of the moondrop are not very nutritious, but their peculiar sweet-sour flavor profile makes them one Thousand Petal's great delicacies";
          127  +		desc = "The fruits of the moondrop are not very nutritious, but their peculiar sweet-sour flavor profile makes them one of Farthest Shadow's great delicacies";
   128    128   		color = lib.color(1,0,.4);
   129    129   		nourish = 10;
   130    130   		hydrate = 0.05;
   131    131   		taste = 1 * 60;
   132    132   		mass = 1;
   133    133   	};
   134    134   	decoration = {
................................................................................
   150    150   		color = lib.color(.7, .4, .8);
   151    151   		drop = simpleDrop(2, 'starlit_eco:dustrose_petal');
   152    152   	};
   153    153   	decoration = {
   154    154   		place_on = 'starlit:greengraze';
   155    155   		fill_ratio = 0.03;
   156    156   		biomes = {'starlit:forest'};
   157         -		y_min = -50;
          157  +		y_min = 0;
   158    158   		y_max = 50;
   159    159   	};
   160    160   }
   161    161   
   162    162   stalkPlantAuto {
   163    163   	id = 'starlit_eco:harrowstalk';
   164    164   	name = "Harrowstalk";
   165    165   	fiber = simpleDrop(2, 'starlit_eco:fiber');
   166    166   	seed = {};
   167    167   	color = lib.color(.3, .2, .1);
   168    168   	decoration = {
   169    169   		place_on = 'starlit:sand';
   170    170   		fill_ratio = 0.03;
   171         -		biomes = {'starlit:ocean', 'starlit:desert'};
   172         -		y_min = -30;
          171  +		biomes = {'starlit:desert'};
          172  +		y_min = 0;
   173    173   		y_max = 400;
   174    174   	};
   175    175   }

Modified mods/starlit-eco/trees.lua from [49c5f4ea72] to [9fe2b3bf5d].

   171    171   			thin_branches = true;
   172    172   
   173    173   			fruit = 'starlit_eco:lambent_pine_bulb';
   174    174   			fruit_chance = 0;
   175    175   		};
   176    176   		decorate = {
   177    177   			{ biomes = {'starlit:forest'};
   178         -				place_on = 'starlit:greengraze';
          178  +				place_on = {'starlit:greengraze'};
   179    179   				fill_ratio = 0.004;
   180         -				y_min = -30, y_max = 500;
          180  +				y_min = 0, y_max = 500;
   181    181   				seed = 0xe8190e;
   182    182   			};
   183    183   			{ biomes = {'starlit:steppe'};
   184         -				place_on = 'starlit:greengraze';
          184  +				place_on = {'starlit:greengraze'};
   185    185   				fill_ratio = 0.002;
   186         -				y_min = -30, y_max = 500;
          186  +				y_min = 0, y_max = 500;
   187    187   				seed = 0xe8190e;
   188    188   			};
   189    189   		};
   190    190   	};
   191    191   
   192    192   	['starlit_eco:starblossom'] = {
   193    193   		def = {
................................................................................
   205    205   			iterations = 13;
   206    206   			random_level = 5;
   207    207   		};
   208    208   		decorate = {
   209    209   			{ biomes = {'starlit:forest'};
   210    210   				place_on = 'starlit:greengraze';
   211    211   				fill_ratio = 0.001;
   212         -				y_min = -20, y_max = 512;
          212  +				y_min = 0, y_max = 512;
   213    213   			};
   214    214   		};
   215    215   	};
   216    216   }
   217    217   
   218    218   minetest.register_abm {
   219    219   	label = "lambent pine fruiting";

Modified mods/starlit/species.lua from [1469667980] to [7816834c67].

    19     19   	sprint = {
    20     20   		id = 'sprint';
    21     21   		name = 'Sprint';
    22     22   		desc = 'Put on a short burst of speed at the cost of some stamina';
    23     23   		img = 'starlit-ui-icon-ability-sprint.png';
    24     24   		powerKind = 'maneuver';
    25     25   		run = function(user, ctx)
           26  +			local cost = 10
           27  +			-- unfortunately stat writes are very expensive, so can't draw from stamina
           28  +			-- every single frame
           29  +			local function halt()
           30  +				if user.action.prog.sprint then
           31  +					user:statDelta('stamina', -user.action.prog.sprint.cb)
           32  +					user:deleteOverlay(user.action.prog.sprint.id)
           33  +					user.action.prog.sprint = nil
           34  +				end
           35  +			end
           36  +
           37  +			if ctx.how.state == 'init' then
           38  +				halt()
           39  +				if user:effectiveStat 'stamina' > 0 then
           40  +					user.action.prog.sprint = {
           41  +						cb = 0;
           42  +						id = user:overlay(function(phys) phys.speed = phys.speed * 2 end)
           43  +					}
           44  +				end
           45  +			elseif ctx.how.state == 'prog' then
           46  +				local d = ctx.how.delta
           47  +				local p = user.action.prog.sprint
           48  +				-- is the player currently holding any of WASD
           49  +				local isMoving = bit.band(0x0f, user.entity:get_player_control_bits()) ~= 0
           50  +				if p and isMoving then
           51  +					p.cb = p.cb + cost*d
           52  +					if p.cb >= 10 then
           53  +						user:statDelta('stamina', -10)
           54  +						if user:effectiveStat 'stamina' < 10 then halt() end
           55  +					end
           56  +				end
           57  +			elseif ctx.how.state == 'halt' then
           58  +				halt()
           59  +			end
    26     60   		end;
    27     61   	};
    28     62   }
    29     63   
    30     64   local species = {
    31     65   	human = {
    32     66   		name = 'Human';
................................................................................
    59     93   				end;
    60     94   				stats = {
    61     95   					psiRegen = 1.3;
    62     96   					psiPower = 1.2;
    63     97   					psi = 1.2;
    64     98   					nutrition = .8; -- women have smaller stomachs
    65     99   					hydration = .8;
    66         -					staminaRegen = 1.0;
    67    100   					morale = 0.8; -- you are not She-Bear Grylls
    68    101   				};
    69    102   				traits = {
    70    103   					health = 400;
    71    104   					lungCapacity = .6;
    72    105   					irradiation = 0.8; -- you are smaller, so it takes less rads to kill ya
    73    106   					sturdiness = 0; -- women are more fragile and thus susceptible to blunt force trauma
    74    107   					metabolism = .150; -- kCal/s
    75    108   					painTolerance = 0.4;
    76    109   					dehydration = 10e-4; -- L/s
    77    110   					speed = 1.1;
          111  +					staminaRegen = 30.0;
    78    112   				};
    79    113   			};
    80    114   			male = {
    81    115   				name = 'Human Male';
    82    116   				eyeHeight = 1.6;
    83    117   				stats = {
    84    118   					psiRegen = 1.0;
    85    119   					psiPower = 1.0;
    86    120   					psi = 1.0;
    87    121   					nutrition = 1.0;
    88    122   					hydration = 1.0;
    89         -					staminaRegen = .7; -- men are strong but have inferior endurance
          123  +					staminaRegen = 20; -- men are strong but have inferior endurance
    90    124   				};
    91    125   				traits = {
    92    126   					health = 500;
    93    127   					painTolerance = 1.0;
    94    128   					lungCapacity = 1.0;
    95    129   					sturdiness = 0.3;
    96    130   					metabolism = .150; -- kCal/s

Modified mods/starlit/stats.lua from [93739694fe] to [0892085f88].

    24     24   starlit.world.stats = {
    25     25   	psi        = {min = 0, max = 500, base = 0, desc = U('ψ', 10), color = C(320), name = 'Numina'};
    26     26   	-- numina is measured in daψ
    27     27   	warmth     = {min = -1000, max = 1000, base = 0, desc = U('°C', 10, true), color = C(5), name = 'Warmth'};
    28     28   	-- warmth in measured in d°C
    29     29   	fatigue    = {min = 0, max = 76 * 60, base = 0, desc = U('hr', 60, true), color = C(288,.3,.5), name = 'Fatigue', srzType = T.decimal};
    30     30   	-- fatigue is measured in minutes one needs to sleep to cure it
    31         -	stamina    = {min = 0, max = 20 * 100, base = true, desc = U('m', 100), color = C(88), name = 'Stamina'};
           31  +	stamina    = {min = 0, max = 40 * 100, base = true, desc = U('m', 100), color = C(88), name = 'Stamina'};
    32     32   	-- stamina is measured in how many 10th-nodes (== cm) one can sprint
    33     33   	nutrition  = {min = 0, max = 8000, base = 0, desc = U('kCal', 1, true), color = C(43,.5,.4), name = 'Nutrition', srzType = T.decimal};
    34     34   	-- hunger is measured in kcalories one must consume to cure it. at 0, you start dying
    35     35   	hydration  = {min = 0, max = 4, base = 0, desc = U('L', 1), color = C(217, .25,.4), name = 'Hydration', srzType = T.decimal};
    36     36   	-- thirst is measured in L of H²O required to cure it
    37     37   	morale     = {min = 0, max = 10 * 24 * 60, base = true, desc = U('hr', 60, true), color = C(0,0,.8), name = 'Morale', srzType = T.decimal};
    38     38   	-- morale is measured in minutes. e.g. at base rate morale degrades by

Modified mods/starlit/terrain.lua from [43f9137bd9] to [4e1556f916].

    39     39   	};
    40     40   })
    41     41   
    42     42   
    43     43   minetest.register_node('starlit:sand', {
    44     44   	description = T 'Sand';
    45     45   	tiles = {'starlit-terrain-sand.png'};
    46         -	groups = {looseClump = 1, sand  = 1};
           46  +	groups = {looseClump = 1, sand = 1, falling_node = 1};
    47     47   	drop = '';
    48     48   	sounds = sandSounds;
    49     49   	_starlit = {
    50     50   		kind = 'block';
    51     51   		fab = starlit.type.fab { element = { silicon = 25 } };
    52     52   	};
    53     53   })
           54  +
           55  +minetest.register_node('starlit:lifesilt', {
           56  +	description = T 'Lifesilt';
           57  +	tiles = {'starlit-terrain-lifesilt.png'};
           58  +	groups = {looseClump = 1, lifesilt = 1, falling_node = 1};
           59  +	drop = '';
           60  +	sounds = sandSounds;
           61  +	_starlit = {
           62  +		kind = 'block';
           63  +		fab = starlit.type.fab { element = { carbon = 8, silicon = 4 } };
           64  +	};
           65  +})
           66  +
    54     67   minetest.register_craftitem('starlit:soil_clump', {
    55     68   	short_description = T 'Soil';
    56     69   	description = starlit.ui.tooltip {
    57     70   		title = T 'Soil';
    58     71   		desc = 'A handful of nutrient-packed soil, suitable for growing plants';
    59     72   		color = lib.color(0.3,0.2,0.1);
    60     73   	};
................................................................................
   105    118   
   106    119   
   107    120   starlit.terrain.createGrass {
   108    121   	name = 'starlit:greengraze';
   109    122   	desc = T 'Greengraze';
   110    123   	img = 'starlit-terrain-greengraze';
   111    124   	fab = starlit.type.fab {
          125  +		element = { carbon = 12; };
          126  +		time = { shred = 2.5; };
          127  +	};
          128  +}
          129  +
          130  +starlit.terrain.createGrass {
          131  +	name = 'starlit:undergloam';
          132  +	desc = T 'Undergloam';
          133  +	-- fungal carpet
          134  +	img = 'starlit-terrain-undergloam';
          135  +	fab = starlit.type.fab {
   112    136   		element = {
   113    137   			carbon = 12;
   114    138   		};
   115         -		time = {
   116         -			shred = 2.5;
   117         -		};
          139  +		time = { shred = 2.5; };
   118    140   	};
   119    141   }
   120    142   
   121    143   for _, w in pairs {false,true} do
   122    144   	minetest.register_node('starlit:liquid_water' .. (w and '_flowing' or ''), {
   123    145   		description = T 'Water';
   124    146   		drawtype = 'liquid';
................................................................................
   164    186   end
   165    187   
   166    188   
   167    189   starlit.world.mineral.foreach('starlit:mineral_generate', {}, function(name,m)
   168    190   	local node = string.format('starlit:mineral_%s', name)
   169    191   	local grp = {mineral = 1}
   170    192   	minetest.register_node(node, {
   171         -		description = m.desc;
          193  +		short_description = m.name;
          194  +		description = starlit.ui.tooltip {
          195  +			title = m.name;
          196  +			desc = m.desc;
          197  +			color = m.tone;
          198  +		};
   172    199   		tiles = m.tiles or 
   173    200   				(m.tone and {
   174         -					string.format('default_stone.png^[colorizehsl:%s:%s:%s',
   175         -						m.tone.hue, m.tone.sat, m.tone.lum)
   176         -				}) or {'default_stone.png'};
          201  +					lib.image'starlit-terrain-granite.png':shift(m.tone):render()
          202  +				}) or nil;
   177    203   		groups = grp;
   178    204   		drop = m.rocks or '';
   179    205   		sounds = hardSounds;
   180    206   		_starlit = {
   181    207   			kind = 'block';
   182    208   			elements = m.elements;
   183    209   			fab = m.fab;
   184    210   			recover = m.recover;
   185    211   			recover_vary = m.recover_vary;
   186    212   		};
   187    213   	})
   188    214   	if not m.excludeOre then
   189    215   		local seed = 0
   190         -		grp.ore = 1
          216  +-- 		grp.ore = 1
   191    217   		for i = 1, #m.name do
   192         -			seed = seed*50 + string.byte(name, i)
          218  +			seed = seed*50 + string.byte(m.name, i)
   193    219   		end
   194    220   		minetest.register_ore {
   195    221   			ore = node;
   196    222   			ore_type = m.dist.kind;
   197         -			wherein = {m.dist.among};
          223  +			wherein = m.dist.among;
   198    224   			clust_scarcity = m.dist.rare;
   199    225   			y_max = m.dist.height[1], y_min = m.dist.height[2];
          226  +			column_height_min = m.dist.sheetCols and m.dist.sheetCols[1] or nil;
          227  +			column_height_max = m.dist.sheetCols and m.dist.sheetCols[2] or nil;
   200    228   			noise_params = m.dist.noise or {
   201         -				offset = 28;
   202         -				scale = 16;
          229  +				scale = 1;
   203    230   				spread = vector.new(128,128,128);
   204    231   				seed = seed;
   205         -				octaves = 1;
          232  +				octaves = 2;
   206    233   			};
   207    234   		}
   208    235   	end
   209    236   end)
   210    237   
   211    238   starlit.world.mineral.link('feldspar', {
   212         -	desc = T 'Feldspar';
          239  +	name = T 'Feldspar';
          240  +	tiles = {'starlit-terrain-feldspar.png'};
   213    241   	excludeOre = true;
   214    242   	recover = starlit.type.fab {
   215         -		time = {
   216         -			shred = 3;
   217         -		};
   218         -		cost = {
   219         -			shredPower = 3;
          243  +		time = { shred = 3; };
          244  +		cost = { shredPower = 3; };
          245  +	};
          246  +	recover_vary = function(rng, ctx)
          247  +		-- print('vary!', rng:int(), rng:int(0,10))
          248  +		return starlit.type.fab {
          249  +			element = {
          250  +				aluminum  = rng:int(0,4);
          251  +				potassium = rng:int(0,2);
          252  +				calcium   = rng:int(0,2);
          253  +			}
   220    254   		};
          255  +	end;
          256  +})
          257  +
          258  +starlit.world.mineral.link('granite', {
          259  +	name = T 'Granite';
          260  +	tiles = {'starlit-terrain-granite.png'};
          261  +	dist = {
          262  +		kind = 'sheet';
          263  +		among = 'starlit:feldspar';
          264  +		height = {-200,30};
          265  +		sheetCols = {1, 16};
          266  +	};
          267  +	recover = starlit.type.fab {
          268  +		time = { shred = 4; };
          269  +		cost = { shredPower = 8; };
   221    270   	};
   222    271   	recover_vary = function(rng, ctx)
   223    272   		-- print('vary!', rng:int(), rng:int(0,10))
   224    273   		return starlit.type.fab {
   225    274   			element = {
   226    275   				aluminum  = rng:int(0,4);
   227    276   				potassium = rng:int(0,2);

Modified mods/starlit/user.lua from [910641ec39] to [e60d6be4a9].

   907    907   			local stats = starlit.world.food.effectiveStats(fd)
   908    908   
   909    909   			return stack
   910    910   		end;
   911    911   	};
   912    912   }
   913    913   
   914         -local biointerval = 3.0
          914  +local biointerval = 1.0
   915    915   starlit.startJob('starlit:bio', biointerval, function(delta)
   916    916   	for id, u in pairs(starlit.activeUsers) do
   917         -		local p = u.pheno
   918         -		local bmr = p:trait 'metabolism' * biointerval
   919         -		-- TODO apply modifiers
          917  +		if u:effectiveStat 'health' ~= 0 then
          918  +			local bmr = u:phenoTrait 'metabolism' * biointerval
          919  +			-- TODO apply modifiers
          920  +
          921  +			local dehydration = u:phenoTrait 'dehydration' * biointerval
          922  +			-- you dehydrate faster in higher temp
          923  +			dehydration = dehydration * math.max(1, starlit.world.climate.temp(u.entity:get_pos()) / 10)
          924  +
          925  +			u:statDelta('nutrition', -bmr)
          926  +			u:statDelta('hydration', -dehydration)
          927  +
          928  +			local moralePenalty = -1 -- 1min/min
          929  +			local fatiguePenalty = 1 -- 1min/min
          930  +			local heatPenalty = 1 -- stamina regen is divided by this
          931  +
          932  +			do local warmth = u:effectiveStat 'warmth'
          933  +				local tempRange = u:species().tempRange
          934  +				local tComfMin, tComfMax = tempRange.comfort[1], tempRange.comfort[2]
          935  +				local tempDiff = 0
          936  +				if warmth < tComfMin then
          937  +					tempDiff = tComfMin - warmth
          938  +				elseif warmth > tComfMax then
          939  +					tempDiff = warmth-tComfMax
          940  +				end
          941  +-- 				print('tempDiff', tComfMin, tComfMax, tempDiff)
          942  +				local tempPenalty = tempDiff/3
          943  +				moralePenalty = moralePenalty + tempPenalty
          944  +				heatPenalty = heatPenalty + tempPenalty
          945  +			end
          946  +
          947  +			-- penalize heavy phys. activity
          948  +			local stamina, sp = u:effectiveStat 'stamina'
          949  +			fatiguePenalty = fatiguePenalty * (1 + 9*(1-sp))
          950  +
          951  +			local food = u:effectiveStat 'nutrition'
          952  +			local water = u:effectiveStat 'hydration'
          953  +			local rads = u:effectiveStat 'irradiation'
          954  +			if food < 1000 then moralePenalty = moralePenalty + (1 - (food/1000)) * 5 end
          955  +			if water < 1   then moralePenalty = moralePenalty + (1 - (water/1)) * 10 end
   920    956   
   921         -		local dehydration = p:trait 'dehydration' * biointerval
   922         -		-- you dehydrate faster in higher temp
   923         -		dehydration = dehydration * math.max(1, starlit.world.climate.temp(u.entity:get_pos()) / 10)
          957  +			if rads > 0 then
          958  +				u:statDelta('irradiation', -0.0001 * biointerval)
          959  +				local moraleDrainFac = 2^(rads / 2)
          960  +				moralePenalty = moralePenalty * moraleDrainFac
          961  +			end
   924    962   
   925         -		u:statDelta('nutrition', -bmr)
   926         -		u:statDelta('hydration', -dehydration)
   927         -
   928         -		local moralePenalty = -1 -- 1min/min
   929         -		local fatiguePenalty = 1 -- 1min/min
   930         -		local heatPenalty = 1 -- stamina regen is divided by this
          963  +			u:statDelta('morale', moralePenalty * biointerval)
          964  +			u:statDelta('fatigue', fatiguePenalty * biointerval)
   931    965   
   932         -		do local warmth = u:effectiveStat 'warmth'
   933         -			local tempRange = u:species().tempRange
   934         -			local tComfMin, tComfMax = tempRange.comfort[1], tempRange.comfort[2]
   935         -			local tempDiff = 0
   936         -			if warmth < tComfMin then
   937         -				tempDiff = math.abs(warmth-tComfMin)
   938         -			elseif warmth > tComfMax then
   939         -				tempDiff = math.abs(warmth-tComfMax)
          966  +			if food == 0 then -- starvation
          967  +				u:statDelta('health', -5*biointerval)
   940    968   			end
   941         -			moralePenalty = moralePenalty + tempDiff
   942         -			heatPenalty = heatPenalty + tempDiff
   943         -		end
   944    969   
   945         -		-- penalize heavy phys. activity
   946         -		local stamina, sp = u:effectiveStat 'stamina'
   947         -		fatiguePenalty = fatiguePenalty * (1 + 9*(1-sp))
          970  +			if water == 0 then -- dying of thirst
          971  +				u:statDelta('health', -20*biointerval)
          972  +			end
   948    973   
   949         -		local food = u:effectiveStat 'nutrition'
   950         -		local water = u:effectiveStat 'hydration'
   951         -		local rads = u:effectiveStat 'irradiation'
   952         -		if food < 1000 then moralePenalty = moralePenalty + (1 - (food/1000)) * 5 end
   953         -		if water < 1   then moralePenalty = moralePenalty + (1 - (water/1)) * 10 end
   954         -
   955         -		if rads > 0 then
   956         -			u:statDelta('irradiation', -0.0001 * biointerval)
   957         -			local moraleDrainFac = 2^(rads / 2)
   958         -			moralePenalty = moralePenalty * moraleDrainFac
   959         -		end
   960         -
   961         -		u:statDelta('morale', moralePenalty * biointerval)
   962         -		u:statDelta('fatigue', fatiguePenalty * biointerval)
   963         -
   964         -		if food == 0 then -- starvation
   965         -			u:statDelta('health', -5*biointerval)
   966         -		end
   967         -
   968         -		if water == 0 then -- dying of thirst
   969         -			u:statDelta('health', -20*biointerval)
   970         -		end
   971         -
   972         -		if sp < 1.0 then
   973         -			u:statDelta('stamina', u:effectiveStat 'staminaRegen' / heatPenalty)
          974  +			if sp < 1.0 then
          975  +				u:statDelta('stamina', u:phenoTrait('staminaRegen',1) / heatPenalty)
          976  +-- 				print('stam', u:effectiveStat 'stamina', u:phenoTrait('staminaRegen',1) / heatPenalty, heatPenalty)
          977  +			end
   974    978   		end
   975    979   	end
   976    980   end)
   977    981   
   978    982   local cbit = {
   979    983   	up   = 0x001;
   980    984   	down = 0x002;

Modified mods/starlit/world.lua from [cdaabd4e00] to [d79dc9efc2].

     3      3   
     4      4   function world.date()
     5      5   	local days = minetest.get_day_count()
     6      6   	local year = math.floor(days / world.planet.orbit);
     7      7   	local day = days % world.planet.orbit;
     8      8   	return {
     9      9   		year = year, day = day;
    10         -		season = day / world.planet.orbit;
           10  +		season = day / world.planet.orbit + 0.5; -- begin summer
    11     11   	}
    12     12   end
    13     13   local lerp = lib.math.lerp
    14     14   
    15     15   local function gradient(grad, pos)
    16     16   	local n = #grad
    17     17   	if n == 1 then return grad[1] end
................................................................................
    18     18   	local op = pos*(n-1)
    19     19   	local idx = math.floor(op)
    20     20   	local t = op-idx
    21     21   	return lerp(t, grad[1 + idx], grad[2 + idx])
    22     22   end
    23     23   
    24     24   local altitudeCooling = 10 / 100
           25  +local heatRange = {min = -70, max = 70} -- translate mt temps into real temps
    25     26   
    26     27   -- this function provides the basis for temperature calculation,
    27     28   -- which is performed by adding this value to the ambient temperature,
    28     29   -- determined by querying nearby group:heatSource items in accordance
    29     30   -- with the inverse-square law
    30     31   function world.climate.eval(pos, tod, season)
    31     32   	local data = minetest.get_biome_data(pos)
    32     33   	local biome = world.ecology.biomes.db[minetest.get_biome_name(data.biome)]
    33     34   	local heat, humid = data.heat, data.humidity
           35  +	heat = lerp(heat/100, heatRange.min, heatRange.max)
    34     36   	tod = tod or minetest.get_timeofday()
    35     37   	heat = lerp(math.abs(tod - 0.5)*2, heat, heat + biome.nightTempDelta)
           38  +-- 	print('base heat', heat)
    36     39   
    37     40   	local td = world.date()
    38     41   	heat = heat + gradient(biome.seasonalTemp, season or td.season)
           42  +-- 	print('seasonal heat', heat)
    39     43   	if pos.y > 0 then
    40     44   		heat = heat - pos.y*altitudeCooling 
    41     45   	end
           46  +-- 	print('altitude heat', heat)
    42     47   
    43     48   	return {
    44     49   		surfaceTemp = heat;
    45     50   		waterTemp = heat + biome.waterTempDelta;
    46     51   		surfaceHumid = humid;
    47     52   	}
    48     53   end

Modified starlit.ct from [990b095f3f] to [415d01ad10].

    40     40   
    41     41   ### shadows
    42     42   i was delighted to see dynamic shadows land in minetest, and i hope the implementation will eventually mature. however, as it stands, there are severe issues with shadows that make them essentially incompatible with complex meshes like the Starlit player character meshes. for the sake of those who don't mind these glitches, Starlit does enable shadows, but i unfortunately have to recommend that you disable them until the minetest devs get their act together on this feature.
    43     43   
    44     44   ## gameplay
    45     45   the most important thing to understand about starlit is that is is [*mean], by design.
    46     46   
    47         -* chance plays an important role. your escape pod might land in the midst of a lush, temperate forest with plenty of nearby shipwrecks to scavenge. or it might land in the exact geographic center of a vast, harsh desert that your suit's cooling systems can't protect you from, ten klicks from anything of value. "unfair", you say? tough. Thousand Petal doesn't care about your feelings.
           47  +* chance plays an important role. your escape pod might land in the midst of a lush, temperate forest with plenty of nearby shipwrecks to scavenge. or it might land in the exact geographic center of a vast, harsh desert that your suit's cooling systems can't protect you from, ten klicks from anything of value. "unfair", you say? tough. Farthest Shadow doesn't care about your feelings.
    48     48   * death is much worse than a slap on the wrist. when you die, you drop your possessions and your suit, and respawn naked at your spawn point. this is a serious danger, as you might be kilometers away from your spawn point -- and there's no guarantee someone else won't take your suit before you can find your way back to it. good luck crossing long distances without climate control! if you haven't carefully prepared for this eventuality by keeping a spare suit by your spawn point, death can be devastating, to the point of making the game unsurvivable without another player's help. 
    49     49   
    50     50   starlit is somewhat unusual in how it uses the minetest engine. it's a voxel game but not of the minecraft variety.
    51     51   
    52     52   ### controls
    53     53   summon your Suit Interface by pressing the [*E] / [*Inventory] key. this will allow you to move items around in your inventory, but more importantly, it also allows you select or configure your Interaction Mode.
    54     54